Skip to content

Delivery Strategies

The Java SDK supports three delivery strategies for receiving emails. This guide covers when to use each strategy and how to configure them for optimal performance.

StrategyDescription
AUTOStarts with SSE, falls back to polling (recommended)
SSEReal-time via Server-Sent Events
POLLINGPeriodic HTTP polling
AspectSSEPolling
LatencyInstant (~0ms)Poll interval (1-30s)
ConnectionPersistentPer request
Resource usageLowerHigher
Firewall friendlySometimesAlways
RecoveryAuto-reconnectNatural
Best forReal-time needsCI/CD, firewalls

The default and recommended strategy. It provides the best of both worlds - real-time delivery when available, with automatic fallback to polling when needed.

import com.vaultsandbox.client.ClientConfig;
import com.vaultsandbox.client.StrategyType;
ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.AUTO)
.build();
  1. Checks if SSE is supported at initialization (connectivity check)
  2. If SSE is supported, uses SSE for real-time notifications
  3. If SSE fails permanently (after max reconnect attempts), falls back to polling
  4. Migrates active subscriptions during fallback
  5. Fallback is transparent to application code
ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.AUTO)
// SSE settings (used first)
.sseReconnectInterval(Duration.ofSeconds(5))
.sseMaxReconnectAttempts(10)
// Polling settings (fallback)
.pollInterval(Duration.ofSeconds(2))
.maxBackoff(Duration.ofSeconds(30))
.build();
import com.vaultsandbox.client.strategy.AutoStrategy;
// After client initialization, check which strategy is active
AutoStrategy autoStrategy = ...; // Retrieved from client internals
boolean usingSse = autoStrategy.isUsingSse();
System.out.println("Using SSE: " + usingSse);

Real-time email delivery via Server-Sent Events. Uses a persistent HTTP connection for instant notifications.

ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.SSE)
.sseReconnectInterval(Duration.ofSeconds(5))
.sseMaxReconnectAttempts(10)
.build();
  • Instant email notification (~0ms latency)
  • Lower server load (single persistent connection)
  • Efficient resource usage
  • Automatic reconnection on temporary failures
  • May be blocked by some firewalls/proxies
  • Requires persistent connection
  • May not work in all CI environments
  • Connection limits in some environments
OptionTypeDefaultDescription
sseReconnectIntervalDuration5sTime between reconnection attempts
sseMaxReconnectAttemptsint10Max reconnection attempts before failure
  • Development environments
  • Real-time monitoring applications
  • Interactive testing
  • Environments with stable connections
  • When minimal latency is critical

SSE automatically reconnects on connection failures with exponential backoff:

ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.SSE)
.sseReconnectInterval(Duration.ofSeconds(5)) // Base interval
.sseMaxReconnectAttempts(10) // Fails after 10 attempts
.build();

Reconnection Flow:

  1. Connection lost
  2. Wait sseReconnectInterval * 2^attempts (exponential backoff)
  3. Attempt reconnection
  4. If failed, increment attempt counter
  5. Reset counter on successful reconnection
  6. Throw SseException after sseMaxReconnectAttempts failures

Periodic polling for new emails. Uses standard HTTP requests at regular intervals.

ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.POLLING)
.pollInterval(Duration.ofSeconds(2))
.maxBackoff(Duration.ofSeconds(30))
.backoffMultiplier(1.5)
.jitterFactor(0.3)
.build();
  • Works everywhere (no firewall issues)
  • Firewall friendly (standard HTTP requests)
  • Simple request/response model
  • Natural recovery from failures
  • No persistent connections required
  • Higher latency (depends on poll interval)
  • More API requests
  • Slightly higher resource usage
  • Trade-off between latency and request frequency
OptionTypeDefaultDescription
pollIntervalDuration2sBase polling interval
maxBackoffDuration30sMaximum backoff duration
backoffMultiplierdouble1.5Exponential backoff multiplier
jitterFactordouble0.3Random jitter factor (0-1)
  • CI/CD environments
  • Behind restrictive firewalls
  • When reliability is critical
  • Environments with connection limits
  • Corporate networks with proxy restrictions

Polling uses exponential backoff with jitter to prevent thundering herd:

nextInterval = min(
pollInterval * (backoffMultiplier ^ attempts),
maxBackoff
) * (1 + random(-jitterFactor, jitterFactor))

Example sequence (2s base, 1.5x multiplier, 30s max):

AttemptInterval
12s
23s
34.5s
46.75s
510.1s
Max30s

Jitter adds randomness (±30% by default) to spread out requests.

┌─────────────────────────────────────┐
│ Choose Strategy │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Need real-time (<100ms latency)? │
└─────────────────────────────────────┘
│ │
Yes No
│ │
▼ ▼
┌───────────────┐ ┌───────────────────┐
│ Environment │ │ Use POLLING │
│ supports SSE? │ │ or AUTO │
└───────────────┘ └───────────────────┘
│ │
Yes No/Unknown
│ │
▼ ▼
┌───────┐ ┌───────────────────────────┐
│ SSE │ │ Use AUTO (will fallback) │
│ or │ │ or POLLING │
│ AUTO │ └───────────────────────────┘
└───────┘

Quick Decision:

EnvironmentRecommended Strategy
DevelopmentAUTO or SSE
CI/CDPOLLING
Production testsAUTO
Behind firewallPOLLING
Real-time requirementsSSE or AUTO
// Fastest feedback with real-time updates
ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.SSE)
.sseReconnectInterval(Duration.ofSeconds(2))
.build();
// Most reliable in containerized/restricted environments
ClientConfig config = ClientConfig.builder()
.apiKey(System.getenv("VAULTSANDBOX_API_KEY"))
.strategy(StrategyType.POLLING)
.pollInterval(Duration.ofSeconds(2))
.waitTimeout(Duration.ofSeconds(60))
.build();
// Best of both - tries SSE, falls back to polling if needed
ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.AUTO)
.sseReconnectInterval(Duration.ofSeconds(5))
.sseMaxReconnectAttempts(5)
.pollInterval(Duration.ofSeconds(2))
.build();
// Frequent polling for high email volume scenarios
ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.POLLING)
.pollInterval(Duration.ofSeconds(1)) // Frequent checks
.maxBackoff(Duration.ofSeconds(5)) // Quick recovery
.build();
// Fast SSE failure detection and fallback
ClientConfig config = ClientConfig.builder()
.apiKey(apiKey)
.strategy(StrategyType.AUTO)
.sseReconnectInterval(Duration.ofSeconds(2))
.sseMaxReconnectAttempts(3) // Fail fast
.pollInterval(Duration.ofSeconds(1))
.build();
import com.vaultsandbox.client.exception.SseException;
try {
Email email = inbox.waitForEmail(Duration.ofSeconds(30));
} catch (SseException e) {
// SSE connection permanently failed
System.err.println("SSE failed: " + e.getMessage());
// Consider switching to POLLING strategy
}
import com.vaultsandbox.client.exception.TimeoutException;
try {
Email email = inbox.waitForEmail(Duration.ofSeconds(30));
} catch (TimeoutException e) {
// Email not received within timeout
System.err.println("Timeout waiting for email");
}
IssuePossible CauseSolution
SSE not connectingFirewall blockingUse POLLING or AUTO
High latencySlow poll intervalDecrease pollInterval
Missed emailsBackoff too aggressiveReduce maxBackoff
Too many requestsPoll interval too shortIncrease pollInterval
AUTO not falling backMax attempts too highReduce sseMaxReconnectAttempts
Frequent reconnectsUnstable networkIncrease sseReconnectInterval
Connection timeoutsNetwork issuesIncrease httpTimeout
  1. Use AUTO by default - Best balance of performance and reliability
  2. Use POLLING in CI/CD - Most reliable in restricted environments
  3. Configure timeouts appropriately - Match your test requirements
  4. Monitor fallback behavior - Log when strategy changes occur
  5. Test both strategies - Ensure code works with either strategy
  6. Set reasonable reconnect limits - Balance retry vs fail-fast
  7. Use jitter in polling - Prevents thundering herd on server