Delivery Strategies
VaultSandbox Client supports two email delivery strategies: Server-Sent Events (SSE) for real-time updates and Polling for compatibility. SSE is the default strategy, providing near-instant email notifications.
Overview
Section titled “Overview”When you wait for emails or watch for new email notifications, the SDK needs to know when emails arrive. It does this using one of two strategies:
- SSE (Server-Sent Events): Real-time push notifications from the server (default)
- Polling: Periodic checking for new emails
Strategy Comparison
Section titled “Strategy Comparison”| Feature | SSE | Polling |
|---|---|---|
| Latency | Near-instant (~100ms) | Poll interval (default: 2s) |
| Server Load | Lower (persistent connection) | Higher (repeated requests) |
| Network Traffic | Lower (only when emails arrive) | Higher (constant polling) |
| Compatibility | Requires persistent connections | Works everywhere |
| Firewall/Proxy | May be blocked | Always works |
| Battery Impact | Lower (push-based) | Higher (constant requests) |
DeliveryStrategy Enum
Section titled “DeliveryStrategy Enum”public enum DeliveryStrategy{ Sse, // Server-Sent Events (default) Polling // Polling only}SSE Strategy (Default)
Section titled “SSE Strategy (Default)”Server-Sent Events provide real-time push notifications when emails arrive.
Advantages
Section titled “Advantages”- Near-instant delivery: Emails appear within milliseconds
- Lower server load: Single persistent connection
- Efficient: Only transmits when emails arrive
- Battery-friendly: No constant polling
Configuration
Section titled “Configuration”var client = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UseSseDelivery() .WithSseReconnectInterval(TimeSpan.FromSeconds(5)) .WithSseMaxReconnectAttempts(10) .Build();SSE Configuration Options
Section titled “SSE Configuration Options”| Option | Type | Default | Description |
|---|---|---|---|
SseReconnectInterval | TimeSpan | 2 seconds | Initial delay before reconnection |
SseMaxReconnectAttempts | int | 10 | Maximum reconnection attempts |
Reconnection Behavior
Section titled “Reconnection Behavior”SSE uses exponential backoff for reconnections:
1st attempt: SseReconnectInterval (2s)2nd attempt: SseReconnectInterval * 2 (4s)3rd attempt: SseReconnectInterval * 4 (8s)...up to SseMaxReconnectAttemptsExample Usage
Section titled “Example Usage”var client = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UseSseDelivery() .Build();
var inbox = await client.CreateInboxAsync();
// Real-time subscription using IAsyncEnumerable (uses SSE)using var cts = new CancellationTokenSource();
await foreach (var email in inbox.WatchAsync(cts.Token)){ Console.WriteLine($"Instant notification: {email.Subject}");
// Cancel after first email (or based on your logic) if (ShouldStop(email)) { cts.Cancel(); }}
// Waiting also uses SSE (faster than polling)var email = await inbox.WaitForEmailAsync(new WaitForEmailOptions{ Timeout = TimeSpan.FromSeconds(10), Subject = "Welcome", UseRegex = true});When to Use SSE
Section titled “When to Use SSE”- Real-time monitoring: When you need instant email notifications
- Long-running tests: Reduces overall test time
- High email volume: More efficient than polling
- Development/local: Fast feedback during development
Limitations
Section titled “Limitations”- Requires persistent HTTP connection support
- May not work behind some corporate proxies
- Some cloud environments may close long-lived connections
- Requires server-side SSE support
Polling Strategy
Section titled “Polling Strategy”Polling periodically checks for new emails at a configured interval.
Advantages
Section titled “Advantages”- Universal compatibility: Works in all environments
- Firewall-friendly: Standard HTTP requests
- Predictable: Easy to reason about behavior
- Resilient: Automatically recovers from transient failures
Configuration
Section titled “Configuration”var client = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(2)) .Build();Polling Configuration Options
Section titled “Polling Configuration Options”| Option | Type | Default | Description |
|---|---|---|---|
PollInterval | TimeSpan | 2 seconds | How often to poll for emails |
Example Usage
Section titled “Example Usage”var client = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(1)) .Build();
var inbox = await client.CreateInboxAsync();
// Polling-based subscription using IAsyncEnumerableusing var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
await foreach (var email in inbox.WatchAsync(cts.Token)){ Console.WriteLine($"Polled notification: {email.Subject}");}
// Waiting uses polling (checks every PollInterval)var email = await inbox.WaitForEmailAsync(new WaitForEmailOptions{ Timeout = TimeSpan.FromSeconds(10), Subject = "Welcome", UseRegex = true});Choosing Poll Interval
Section titled “Choosing Poll Interval”Different intervals suit different scenarios:
// Fast polling (500ms) - Development/local testingvar fastClient = VaultSandboxClientBuilder.Create() .WithBaseUrl("http://localhost:3000") .WithApiKey("dev-key") .UsePollingDelivery() .WithPollInterval(TimeSpan.FromMilliseconds(500)) .Build();
// Standard polling (2s) - Default, good balancevar standardClient = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(2)) .Build();
// Slow polling (5s) - CI/CD or rate-limited environmentsvar slowClient = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(5)) .Build();When to Use Polling
Section titled “When to Use Polling”- Corporate networks: Restrictive firewall/proxy environments
- CI/CD pipelines: Guaranteed compatibility
- Rate-limited APIs: Avoid hitting request limits
- Debugging: Predictable request timing
- Low email volume: Polling overhead is minimal
Performance Optimization
Section titled “Performance Optimization”For WaitForEmailAsync(), you can override the polling interval per-operation:
// Default client polling: 2svar client = VaultSandboxClientBuilder.Create() .WithBaseUrl("https://smtp.vaultsandbox.com") .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(2)) .Build();
var inbox = await client.CreateInboxAsync();
// Override for specific operation (faster polling)var email = await inbox.WaitForEmailAsync(new WaitForEmailOptions{ Timeout = TimeSpan.FromSeconds(30), PollInterval = TimeSpan.FromSeconds(1) // Check every 1s for this operation});Choosing the Right Strategy
Section titled “Choosing the Right Strategy”Use SSE (Default)
Section titled “Use SSE (Default)”SSE is the default strategy and recommended for most use cases:
var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL")!) .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) // UseSseDelivery() is the default, can be omitted .Build();Best for:
- General testing
- Local development
- Real-time monitoring dashboards
- High-volume email testing
- Latency-sensitive tests
Note: If SSE fails to connect, an SseException will be thrown. Consider using polling if you’re in an environment where SSE may be blocked.
Use Polling
Section titled “Use Polling”When compatibility is more important than speed:
var isCI = Environment.GetEnvironmentVariable("CI") == "true";
var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL")!) .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .WithPollInterval(isCI ? TimeSpan.FromSeconds(3) : TimeSpan.FromSeconds(1)) .Build();Best for:
- CI/CD environments (guaranteed to work)
- Corporate networks with restrictive proxies
- When SSE is known to be problematic
- Rate-limited scenarios
Dependency Injection Configuration
Section titled “Dependency Injection Configuration”Via Options
Section titled “Via Options”{ "VaultSandbox": { "BaseUrl": "https://smtp.vaultsandbox.com", "ApiKey": "your-api-key", "DefaultDeliveryStrategy": "Sse", "PollIntervalMs": 2000, "SseReconnectIntervalMs": 2000, "SseMaxReconnectAttempts": 10 }}// Program.cs or Startup.csservices.AddVaultSandboxClient(options =>{ options.BaseUrl = configuration["VaultSandbox:BaseUrl"]!; options.ApiKey = configuration["VaultSandbox:ApiKey"]!; options.DefaultDeliveryStrategy = Enum.Parse<DeliveryStrategy>( configuration["VaultSandbox:DefaultDeliveryStrategy"] ?? "Sse"); options.PollIntervalMs = int.Parse( configuration["VaultSandbox:PollIntervalMs"] ?? "2000"); options.SseReconnectIntervalMs = int.Parse( configuration["VaultSandbox:SseReconnectIntervalMs"] ?? "2000"); options.SseMaxReconnectAttempts = int.Parse( configuration["VaultSandbox:SseMaxReconnectAttempts"] ?? "10");});Via Configuration Binding
Section titled “Via Configuration Binding”services.AddVaultSandboxClient();services.Configure<VaultSandboxClientOptions>( configuration.GetSection("VaultSandbox"));Environment-Specific Configuration
Section titled “Environment-Specific Configuration”Development
Section titled “Development”Fast feedback with SSE (default):
{ "VaultSandbox": { "BaseUrl": "http://localhost:3000", "DefaultDeliveryStrategy": "Sse" }}// Configuration helperpublic static IVaultSandboxClient CreateClient(IConfiguration configuration){ var builder = VaultSandboxClientBuilder.Create() .WithBaseUrl(configuration["VaultSandbox:BaseUrl"]!) .WithApiKey(configuration["VaultSandbox:ApiKey"]!);
var strategy = configuration["VaultSandbox:DefaultDeliveryStrategy"];
return strategy switch { "Polling" => builder.UsePollingDelivery().Build(), _ => builder.UseSseDelivery().Build() // SSE is default };}Reliable polling:
{ "VaultSandbox": { "BaseUrl": "https://smtp.vaultsandbox.com", "DefaultDeliveryStrategy": "Polling", "PollIntervalMs": 3000 }}Production Testing
Section titled “Production Testing”SSE with tuned reconnection:
var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL")!) .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UseSseDelivery() .WithSseReconnectInterval(TimeSpan.FromSeconds(5)) .WithSseMaxReconnectAttempts(5) .Build();Error Handling
Section titled “Error Handling”SSE Connection Failures
Section titled “SSE Connection Failures”using VaultSandbox.Client.Exceptions;
try{ var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL")!) .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UseSseDelivery() .Build();
var inbox = await client.CreateInboxAsync(); // Use inbox...}catch (SseException ex){ Console.WriteLine($"SSE failed: {ex.Message}"); Console.WriteLine("Falling back to polling...");
// Recreate with polling var fallbackClient = VaultSandboxClientBuilder.Create() .WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL")!) .WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")!) .UsePollingDelivery() .Build();
var inbox = await fallbackClient.CreateInboxAsync(); // Continue with polling...}Handling Watch Errors
Section titled “Handling Watch Errors”try{ await foreach (var email in inbox.WatchAsync(cancellationToken)) { await ProcessEmailAsync(email); }}catch (SseException ex){ Console.WriteLine($"SSE error: {ex.Message}"); // Consider recreating client with polling if SSE is blocked}catch (StrategyException ex){ Console.WriteLine($"Strategy error: {ex.Message}");}catch (OperationCanceledException){ Console.WriteLine("Watch cancelled");}Polling Too Slow
Section titled “Polling Too Slow”If emails arrive slowly with polling:
// Problem: Default 2s polling is too slowvar client = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(2)) .Build();
// Solution 1: Faster pollingvar fasterClient = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromMilliseconds(500)) .Build();
// Solution 2: Use SSE if availablevar sseClient = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UseSseDelivery() .Build();
// Solution 3: Override poll interval for specific waitvar email = await inbox.WaitForEmailAsync(new WaitForEmailOptions{ Timeout = TimeSpan.FromSeconds(10), PollInterval = TimeSpan.FromMilliseconds(500) // Fast polling for this operation});Best Practices
Section titled “Best Practices”1. Use SSE Strategy by Default
Section titled “1. Use SSE Strategy by Default”SSE is the default and provides the best performance:
// Good: Use SSE (default)var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .Build();
// Only specify polling when neededvar ciClient = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() // CI may need guaranteed compatibility .Build();2. Tune for Environment
Section titled “2. Tune for Environment”Configure differently for each environment:
public static IVaultSandboxClient CreateClient(IConfiguration config){ var builder = VaultSandboxClientBuilder.Create() .WithBaseUrl(config["VaultSandbox:BaseUrl"]!) .WithApiKey(config["VaultSandbox:ApiKey"]!);
var isCI = Environment.GetEnvironmentVariable("CI") == "true";
if (isCI) { // CI: Use polling if SSE may be blocked return builder .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(3)) .Build(); } else { // Default: SSE with tuned reconnection return builder .UseSseDelivery() .WithSseReconnectInterval(TimeSpan.FromSeconds(2)) .WithSseMaxReconnectAttempts(10) .Build(); }}3. Handle SSE Gracefully
Section titled “3. Handle SSE Gracefully”Always have a fallback if forcing SSE:
async Task<IVaultSandboxClient> CreateClientWithFallbackAsync(){ try { var client = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UseSseDelivery() .Build();
// Test SSE connectivity var inbox = await client.CreateInboxAsync(); await client.DeleteInboxAsync(inbox.EmailAddress);
return client; } catch (SseException) { Console.WriteLine("SSE unavailable, using polling");
return VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() .Build(); }}4. Don’t Poll Too Aggressively
Section titled “4. Don’t Poll Too Aggressively”Avoid very short polling intervals in production:
// Avoid: Too aggressivevar client = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromMilliseconds(100)) // 100ms - too frequent! .Build();
// Good: Reasonable intervalvar client = VaultSandboxClientBuilder.Create() .WithBaseUrl(url) .WithApiKey(apiKey) .UsePollingDelivery() .WithPollInterval(TimeSpan.FromSeconds(2)) // 2s - balanced .Build();5. Use CancellationToken for Long-Running Operations
Section titled “5. Use CancellationToken for Long-Running Operations”Always provide cancellation support for watch operations:
using var cts = new CancellationTokenSource();
// Cancel after timeoutcts.CancelAfter(TimeSpan.FromMinutes(5));
// Or cancel on Ctrl+CConsole.CancelKeyPress += (_, e) =>{ e.Cancel = true; cts.Cancel();};
try{ await foreach (var email in inbox.WatchAsync(cts.Token)) { Console.WriteLine($"Received: {email.Subject}"); }}catch (OperationCanceledException){ Console.WriteLine("Watch operation cancelled");}Next Steps
Section titled “Next Steps”- Real-time Monitoring Guide - Using
WatchAsyncandIAsyncEnumerable - Configuration Reference - All configuration options
- Error Handling - Handle SSE and strategy errors
- CI/CD Integration - Strategy for CI environments