Skip to content

Chaos Engineering

Chaos engineering allows you to simulate various SMTP failure scenarios and network issues during email testing. This helps verify your application handles email delivery failures gracefully.

Chaos features must be enabled on the gateway server. Check availability:

using VaultSandbox.Client;
await using var client = new VaultSandboxClient(
Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"),
Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")
);
var serverInfo = await client.GetServerInfoAsync();
if (serverInfo.ChaosEnabled)
{
Console.WriteLine("Chaos features available");
}
else
{
Console.WriteLine("Chaos features disabled on this server");
}
using VaultSandbox.Client;
var inbox = await client.CreateInboxAsync(new CreateInboxOptions
{
Chaos = new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 1000,
MaxDelayMs = 5000,
},
},
});
var chaos = await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 1000,
MaxDelayMs = 5000,
},
});
var config = await inbox.GetChaosConfigAsync();
Console.WriteLine($"Chaos enabled: {config.Enabled}");
if (config.Latency != null)
{
Console.WriteLine($"Latency enabled: {config.Latency.Enabled}");
}
await inbox.DisableChaosAsync();
using VaultSandbox.Client;
// Configuration classes
SetChaosConfigOptions // Main configuration
LatencyOptions // Latency injection settings
ConnectionDropOptions // Connection drop settings
RandomErrorOptions // Random error settings
GreylistOptions // Greylisting settings
BlackholeOptions // Blackhole mode settings
PropertyTypeRequiredDescription
EnabledboolYesMaster switch for all chaos features
ExpiresAtDateTimeOffset?NoAuto-disable chaos after this time
LatencyLatencyOptionsNoInject artificial delays
ConnectionDropConnectionDropOptionsNoSimulate connection failures
RandomErrorRandomErrorOptionsNoReturn random SMTP error codes
GreylistGreylistOptionsNoSimulate greylisting behavior
BlackholeBlackholeOptionsNoAccept but silently discard emails

Inject artificial delays into email processing to test timeout handling and slow connections.

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 500, // Minimum delay (default: 500)
MaxDelayMs = 5000, // Maximum delay (default: 10000, max: 60000)
Jitter = true, // Randomize within range (default: true)
Probability = 0.5, // 50% of emails affected (default: 1.0)
},
});
PropertyTypeDefaultDescription
EnabledboolEnable/disable latency injection
MinDelayMsint500Minimum delay in milliseconds
MaxDelayMsint10000Maximum delay in milliseconds (max: 60000)
JitterbooltrueRandomize delay within range. If false, uses MaxDelay
Probabilitydouble1.0Probability of applying delay (0.0-1.0)
  • Test application timeout handling
  • Verify UI responsiveness during slow email delivery
  • Test retry logic with variable delays

Simulate connection failures by dropping SMTP connections.

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
ConnectionDrop = new ConnectionDropOptions
{
Enabled = true,
Probability = 0.3, // 30% of connections dropped
Graceful = false, // Abrupt RST instead of graceful FIN
},
});
PropertyTypeDefaultDescription
EnabledboolEnable/disable connection dropping
Probabilitydouble1.0Probability of dropping connection (0.0-1.0)
GracefulbooltrueUse graceful close (FIN) vs abrupt (RST)
  • Test connection reset handling
  • Verify TCP error recovery
  • Test application behavior when SMTP connections fail mid-delivery

Return random SMTP error codes to test error handling.

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
RandomError = new RandomErrorOptions
{
Enabled = true,
ErrorRate = 0.1, // 10% of emails return errors
ErrorTypes = new[] { RandomErrorType.Temporary }, // Only 4xx errors
},
});
PropertyTypeDefaultDescription
EnabledboolEnable/disable random errors
ErrorRatedouble0.1Probability of returning an error
ErrorTypesRandomErrorType[][RandomErrorType.Temporary]Types of errors to return
TypeSMTP CodesDescription
Temporary4xxTemporary failures, should retry
Permanent5xxPermanent failures, should not retry
  • Test 4xx SMTP error handling and retry logic
  • Test 5xx SMTP error handling and failure notifications
  • Verify application handles both error types correctly

Simulate greylisting behavior where the first delivery attempt is rejected and subsequent retries are accepted.

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Greylist = new GreylistOptions
{
Enabled = true,
RetryWindowMs = 300000, // 5 minute window
MaxAttempts = 2, // Accept on second attempt
TrackBy = GreylistTrackBy.IpSender, // Track by IP and sender combination
},
});
PropertyTypeDefaultDescription
EnabledboolEnable/disable greylisting
RetryWindowMsint300000Window for tracking retries (5 min)
MaxAttemptsint2Attempts before accepting
TrackByGreylistTrackByGreylistTrackBy.IpSenderHow to identify unique delivery attempts
MethodDescription
IpTrack by sender IP only
SenderTrack by sender email only
IpSenderTrack by combination of IP and sender
  • Test SMTP retry behavior when mail servers use greylisting
  • Verify retry intervals and backoff logic
  • Test handling of temporary 4xx rejections

Accept emails but silently discard them without storing.

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Blackhole = new BlackholeOptions
{
Enabled = true,
TriggerWebhooks = false, // Don't trigger webhooks for discarded emails
},
});
PropertyTypeDefaultDescription
EnabledboolEnable/disable blackhole mode
TriggerWebhooksboolfalseTrigger webhooks for discarded emails
  • Test behavior when emails are silently lost
  • Test webhook integration even when emails aren’t stored
  • Simulate email delivery that succeeds at SMTP level but fails at storage

Set chaos to automatically disable after a specific time:

// Enable chaos for 1 hour
var expiresAt = DateTimeOffset.UtcNow.AddHours(1);
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
ExpiresAt = expiresAt,
Latency = new LatencyOptions { Enabled = true, MaxDelayMs = 3000 },
});

After ExpiresAt, chaos is automatically disabled and normal email delivery resumes.

Multiple chaos features can be enabled simultaneously:

await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
// 30% of emails delayed 1-5 seconds
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 1000,
MaxDelayMs = 5000,
Probability = 0.3,
},
// 10% of emails return temporary errors
RandomError = new RandomErrorOptions
{
Enabled = true,
ErrorRate = 0.1,
ErrorTypes = new[] { RandomErrorType.Temporary },
},
});
using VaultSandbox.Client;
async Task TestChaosResilienceAsync()
{
await using var client = new VaultSandboxClient(
Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"),
Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")
);
// Check if chaos is available
var serverInfo = await client.GetServerInfoAsync();
if (!serverInfo.ChaosEnabled)
{
Console.WriteLine("Chaos features not available on this server");
return;
}
// Create inbox with chaos enabled
await using var inbox = await client.CreateInboxAsync(new CreateInboxOptions
{
Chaos = new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 2000,
MaxDelayMs = 5000,
Probability = 0.5,
},
RandomError = new RandomErrorOptions
{
Enabled = true,
ErrorRate = 0.1,
ErrorTypes = new[] { RandomErrorType.Temporary },
},
},
});
Console.WriteLine($"Testing with chaos: {inbox.EmailAddress}");
// Get current chaos configuration
var config = await inbox.GetChaosConfigAsync();
Console.WriteLine($"Chaos enabled: {config.Enabled}");
Console.WriteLine($"Latency enabled: {config.Latency?.Enabled ?? false}");
// Send test emails and verify handling
// Your test logic here...
// Update chaos configuration
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Greylist = new GreylistOptions
{
Enabled = true,
MaxAttempts = 3,
},
});
// More testing...
// Disable chaos for normal operation tests
await inbox.DisableChaosAsync();
}
// Enable greylisting to test retry behavior
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Greylist = new GreylistOptions { Enabled = true, MaxAttempts = 2 },
});
// Send email - first attempt will fail, retry should succeed
await SendEmailAsync(inbox.EmailAddress);
// If your mail sender retries correctly, email should arrive
var email = await inbox.WaitForEmailAsync(new WaitForEmailOptions { Timeout = 60000 });
// Enable high latency
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 10000,
MaxDelayMs = 15000,
},
});
// Test that your application handles timeouts correctly
try
{
await inbox.WaitForEmailAsync(new WaitForEmailOptions { Timeout = 5000 });
}
catch (TimeoutException)
{
// Expected: TimeoutException
Console.WriteLine("Timeout handled correctly");
}
// Enable high error rate
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
RandomError = new RandomErrorOptions
{
Enabled = true,
ErrorRate = 0.8,
ErrorTypes = new[] { RandomErrorType.Temporary, RandomErrorType.Permanent },
},
});
// Test that your application handles errors and retries appropriately
using VaultSandbox.Client;
using VaultSandbox.Client.Exceptions;
try
{
await inbox.SetChaosConfigAsync(new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions { Enabled = true },
});
}
catch (InboxNotFoundException)
{
Console.WriteLine("Inbox not found");
}
catch (ApiException ex) when (ex.StatusCode == 403)
{
Console.WriteLine("Chaos features are disabled on this server");
}
catch (ApiException ex)
{
Console.WriteLine($"API error ({ex.StatusCode}): {ex.Message}");
}
using VaultSandbox.Client;
using Xunit;
public abstract class ChaosTestBase : IAsyncLifetime
{
protected VaultSandboxClient Client { get; private set; } = null!;
protected IInbox Inbox { get; private set; } = null!;
public async Task InitializeAsync()
{
Client = new VaultSandboxClient(
Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"),
Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")
);
var serverInfo = await Client.GetServerInfoAsync();
if (!serverInfo.ChaosEnabled)
{
throw new SkipException("Chaos features not available on this server");
}
Inbox = await Client.CreateInboxAsync(new CreateInboxOptions
{
Chaos = new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 500,
MaxDelayMs = 2000,
},
},
});
}
public async Task DisposeAsync()
{
if (Inbox != null)
{
await Inbox.DisposeAsync();
}
Client?.Dispose();
}
}
public class SlowDeliveryTests : ChaosTestBase
{
[Fact]
public async Task HandlesSlowDelivery()
{
// Your test code here
}
}
using VaultSandbox.Client;
using Xunit;
public class ChaosScenarioTests : IAsyncLifetime
{
private VaultSandboxClient _client = null!;
private IInbox _inbox = null!;
public async Task InitializeAsync()
{
_client = new VaultSandboxClient(
Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"),
Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY")
);
_inbox = await _client.CreateInboxAsync();
}
public async Task DisposeAsync()
{
await _inbox.DeleteAsync();
_client.Dispose();
}
[Theory]
[MemberData(nameof(ChaosConfigurations))]
public async Task TestChaosScenario(string scenarioName, SetChaosConfigOptions config)
{
await _inbox.SetChaosConfigAsync(config);
// Test your application's resilience
// ...
}
public static IEnumerable<object[]> ChaosConfigurations()
{
yield return new object[]
{
"Latency",
new SetChaosConfigOptions
{
Enabled = true,
Latency = new LatencyOptions
{
Enabled = true,
MinDelayMs = 1000,
MaxDelayMs = 3000,
},
},
};
yield return new object[]
{
"RandomError",
new SetChaosConfigOptions
{
Enabled = true,
RandomError = new RandomErrorOptions
{
Enabled = true,
ErrorRate = 0.5,
},
},
};
yield return new object[]
{
"Greylist",
new SetChaosConfigOptions
{
Enabled = true,
Greylist = new GreylistOptions
{
Enabled = true,
MaxAttempts = 2,
},
},
};
}
}