Skip to content

IVaultSandboxClient API

The IVaultSandboxClient is the main entry point for interacting with the VaultSandbox Gateway. It handles authentication, inbox creation, and provides utility methods for managing inboxes.

Use VaultSandboxClientBuilder to create a client instance with fluent configuration:

using VaultSandbox.Client;
// Basic configuration
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey("your-api-key")
.Build();
// With validation (recommended for production)
var client = await VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey("your-api-key")
.BuildAndValidateAsync();

Register the client in your service collection:

// In Program.cs or Startup.cs
services.AddVaultSandboxClient(options =>
{
options.BaseUrl = "https://smtp.vaultsandbox.com";
options.ApiKey = Configuration["VaultSandbox:ApiKey"];
});
// Or bind from configuration
services.AddVaultSandboxClient(Configuration.GetSection("VaultSandbox"));

Configuration in appsettings.json:

{
"VaultSandbox": {
"BaseUrl": "https://smtp.vaultsandbox.com",
"ApiKey": "your-api-key",
"WaitTimeoutMs": 30000,
"PollIntervalMs": 2000
}
}

Inject the client in your services:

public class EmailTestService
{
private readonly IVaultSandboxClient _client;
public EmailTestService(IVaultSandboxClient client)
{
_client = client;
}
}

The builder provides fluent configuration methods for creating a client.

MethodDescription
Create()Static factory method to start building
WithBaseUrl(string)Set the gateway URL
WithApiKey(string)Set the API authentication key
WithHttpTimeout(TimeSpan)HTTP request timeout (default: 30s)
WithWaitTimeout(TimeSpan)Default wait timeout for email operations (default: 30s)
WithPollInterval(TimeSpan)Polling interval for email delivery (default: 2s)
WithMaxRetries(int)Maximum retry attempts for HTTP requests (default: 3)
WithRetryDelay(TimeSpan)Initial delay between retries (default: 1s)
WithSseReconnectInterval(TimeSpan)SSE reconnection delay (default: 5s)
WithSseMaxReconnectAttempts(int)Maximum SSE reconnection attempts (default: 10)
WithDeliveryStrategy(DeliveryStrategy)Set the delivery strategy directly
UseSseDelivery()Use Server-Sent Events for email delivery
UsePollingDelivery()Use polling for email delivery
UseAutoDelivery()Auto-select delivery strategy (default)
WithDefaultInboxTtl(TimeSpan)Default time-to-live for new inboxes
WithLogging(ILoggerFactory)Add logging support
WithHttpClient(HttpClient, bool)Use a custom HttpClient instance (optional: dispose client on cleanup)
Build()Build the client instance
BuildAndValidateAsync(CancellationToken)Build and validate the API key
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY"))
.WithWaitTimeout(TimeSpan.FromSeconds(60))
.WithPollInterval(TimeSpan.FromSeconds(1))
.WithMaxRetries(5)
.WithRetryDelay(TimeSpan.FromSeconds(2))
.UseSseDelivery()
.WithLogging(loggerFactory)
.Build();
// Use custom HttpClient, let the builder manage disposal
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey("your-api-key")
.WithHttpClient(myHttpClient, disposeClient: true)
.Build();
// Use custom HttpClient, manage disposal yourself
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey("your-api-key")
.WithHttpClient(sharedHttpClient, disposeClient: false)
.Build();

Configuration options class for the client.

public sealed class VaultSandboxClientOptions
{
public required string BaseUrl { get; set; }
public required string ApiKey { get; set; }
public int HttpTimeoutMs { get; set; } = 30_000;
public int WaitTimeoutMs { get; set; } = 30_000;
public int PollIntervalMs { get; set; } = 2_000;
public int MaxRetries { get; set; } = 3;
public int RetryDelayMs { get; set; } = 1_000;
public int SseReconnectIntervalMs { get; set; } = 5_000;
public int SseMaxReconnectAttempts { get; set; } = 10;
public DeliveryStrategy DefaultDeliveryStrategy { get; set; } = DeliveryStrategy.Auto;
public int DefaultInboxTtlSeconds { get; set; } = 3600;
public void Validate();
}

Creates a new email inbox with automatic key generation and encryption setup.

Task<IInbox> CreateInboxAsync(
CreateInboxOptions? options = null,
CancellationToken cancellationToken = default)
  • options (optional): Configuration for the inbox
  • cancellationToken: Cancellation token for the operation
public sealed class CreateInboxOptions
{
public string? EmailAddress { get; set; }
public TimeSpan? Ttl { get; set; }
}
PropertyTypeDescription
TtlTimeSpan?Time-to-live for the inbox (min: 60s, max: 7 days)
EmailAddressstring?Request a specific email address (max 254 chars)

Task<IInbox> - The created inbox instance

// Create inbox with default settings
var inbox = await client.CreateInboxAsync();
Console.WriteLine($"Send email to: {inbox.EmailAddress}");
// Create inbox with custom TTL (1 hour)
var inbox = await client.CreateInboxAsync(new CreateInboxOptions
{
Ttl = TimeSpan.FromHours(1)
});
// Request specific email address
var inbox = await client.CreateInboxAsync(new CreateInboxOptions
{
EmailAddress = "[email protected]"
});
  • ApiException - API-level error (invalid request, permission denied)
  • NetworkException - Network connection failure
  • InboxAlreadyExistsException - Requested email address is already in use

Deletes a specific inbox by email address.

Task DeleteInboxAsync(string emailAddress, CancellationToken cancellationToken = default)
  • emailAddress: The email address of the inbox to delete
  • cancellationToken: Cancellation token for the operation
await client.DeleteInboxAsync("[email protected]");
Console.WriteLine("Inbox deleted");

Deletes all inboxes associated with the current API key. Useful for cleanup in test environments.

Task<int> DeleteAllInboxesAsync(CancellationToken cancellationToken = default)

Task<int> - Number of inboxes deleted

var deleted = await client.DeleteAllInboxesAsync();
Console.WriteLine($"Deleted {deleted} inboxes");

Use this in test cleanup to avoid orphaned inboxes:

[TearDown]
public async Task Cleanup()
{
var deleted = await _client.DeleteAllInboxesAsync();
if (deleted > 0)
{
Console.WriteLine($"Cleaned up {deleted} orphaned inboxes");
}
}

Retrieves information about the VaultSandbox Gateway server.

Task<ServerInfo> GetServerInfoAsync(CancellationToken cancellationToken = default)

Task<ServerInfo> - Server information record

public sealed record ServerInfo
{
public required string ServerSigPk { get; init; }
public required string Context { get; init; }
public required int MaxTtl { get; init; }
public required int DefaultTtl { get; init; }
public required bool SseConsole { get; init; }
public required IReadOnlyList<string> AllowedDomains { get; init; }
}
PropertyTypeDescription
ServerSigPkstringBase64URL-encoded server signing public key for ML-DSA-65
ContextstringContext string for the encryption scheme
MaxTtlintMaximum time-to-live for inboxes in seconds
DefaultTtlintDefault time-to-live for inboxes in seconds
SseConsoleboolWhether the server SSE console is enabled
AllowedDomainsIReadOnlyList<string>List of domains allowed for inbox creation
var info = await client.GetServerInfoAsync();
Console.WriteLine($"Server: {info.Context}");
Console.WriteLine($"Max TTL: {info.MaxTtl}s, Default TTL: {info.DefaultTtl}s");
Console.WriteLine($"Allowed domains: {string.Join(", ", info.AllowedDomains)}");

Validates the API key with the server.

Task<bool> ValidateApiKeyAsync(CancellationToken cancellationToken = default)

Task<bool> - true if the API key is valid

var isValid = await client.ValidateApiKeyAsync();
if (!isValid)
{
throw new InvalidOperationException("Invalid API key");
}

Useful for verifying configuration before running tests:

[OneTimeSetUp]
public async Task Setup()
{
_client = VaultSandboxClientBuilder.Create()
.WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"))
.WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY"))
.Build();
var isValid = await _client.ValidateApiKeyAsync();
if (!isValid)
{
throw new InvalidOperationException("VaultSandbox API key is invalid");
}
}

Monitors multiple inboxes simultaneously for new emails.

InboxMonitor MonitorInboxes(params IInbox[] inboxes)
  • inboxes: Array of inbox instances to monitor

InboxMonitor - Monitor for multi-inbox watching

var inbox1 = await client.CreateInboxAsync();
var inbox2 = await client.CreateInboxAsync();
var monitor = client.MonitorInboxes(inbox1, inbox2);
await foreach (var evt in monitor.WatchAsync(cancellationToken))
{
Console.WriteLine($"New email in {evt.InboxAddress}: {evt.Email.Subject}");
}

See InboxMonitor for more details.


Imports a previously exported inbox, restoring all data and encryption keys.

Task<IInbox> ImportInboxAsync(
InboxExport export,
CancellationToken cancellationToken = default)
  • export: Previously exported inbox data
  • cancellationToken: Cancellation token for the operation

Task<IInbox> - The imported inbox instance

var exportedData = JsonSerializer.Deserialize<InboxExport>(savedJson);
var inbox = await client.ImportInboxAsync(exportedData);
Console.WriteLine($"Imported inbox: {inbox.EmailAddress}");
// Use inbox normally
var emails = await inbox.GetEmailsAsync();
  • InboxAlreadyExistsException - Inbox is already imported in this client
  • InvalidImportDataException - Import data is invalid or corrupted
  • ApiException - Server rejected the import (inbox may not exist)

Imports an inbox from a JSON file.

Task<IInbox> ImportInboxFromFileAsync(
string filePath,
CancellationToken cancellationToken = default)
  • filePath: Path to the exported inbox JSON file
  • cancellationToken: Cancellation token for the operation

Task<IInbox> - The imported inbox instance

// Import from file
var inbox = await client.ImportInboxFromFileAsync("./backup/inbox.json");
Console.WriteLine($"Imported inbox: {inbox.EmailAddress}");
// Monitor for new emails
await foreach (var email in inbox.WatchAsync(cancellationToken))
{
Console.WriteLine($"New email: {email.Subject}");
}
  • Test reproducibility across runs
  • Sharing inboxes between environments
  • Manual testing workflows
  • Debugging production issues

Exports an inbox to a JSON file on disk.

Task ExportInboxToFileAsync(
IInbox inbox,
string filePath,
CancellationToken cancellationToken = default)
  • inbox: Inbox instance to export
  • filePath: Path where the JSON file will be written
  • cancellationToken: Cancellation token for the operation
var inbox = await client.CreateInboxAsync();
// Export to file
await client.ExportInboxToFileAsync(inbox, "./backup/inbox.json");
Console.WriteLine("Inbox exported to ./backup/inbox.json");

Exported data contains private encryption keys. Store securely and never commit to version control.

The InboxMonitor class allows you to monitor multiple inboxes simultaneously using IAsyncEnumerable.

var inbox1 = await client.CreateInboxAsync();
var inbox2 = await client.CreateInboxAsync();
var monitor = client.MonitorInboxes(inbox1, inbox2);

Streams email arrival events from all monitored inboxes.

IAsyncEnumerable<InboxEmailEvent> WatchAsync(CancellationToken cancellationToken = default)

IAsyncEnumerable<InboxEmailEvent> - Stream of email events

public sealed record InboxEmailEvent(IInbox Inbox, Email Email)
{
public IInbox Inbox { get; } = Inbox;
public Email Email { get; } = Email;
public string InboxAddress => Inbox.EmailAddress;
}
var monitor = client.MonitorInboxes(inbox1, inbox2);
await foreach (var evt in monitor.WatchAsync(cancellationToken))
{
Console.WriteLine($"Email received in {evt.InboxAddress}");
Console.WriteLine($"Subject: {evt.Email.Subject}");
}

Stops monitoring and cleans up resources.

await monitor.DisposeAsync();
using VaultSandbox.Client;
async Task MonitorMultipleInboxes(CancellationToken cancellationToken)
{
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl("https://smtp.vaultsandbox.com")
.WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY"))
.Build();
// Create multiple inboxes
var inbox1 = await client.CreateInboxAsync();
var inbox2 = await client.CreateInboxAsync();
Console.WriteLine($"Inbox 1: {inbox1.EmailAddress}");
Console.WriteLine($"Inbox 2: {inbox2.EmailAddress}");
// Monitor both inboxes
await using var monitor = client.MonitorInboxes(inbox1, inbox2);
await foreach (var evt in monitor.WatchAsync(cancellationToken))
{
Console.WriteLine($"\nNew email in {evt.InboxAddress}:");
Console.WriteLine($" Subject: {evt.Email.Subject}");
Console.WriteLine($" From: {evt.Email.From}");
}
// Clean up
await client.DeleteInboxAsync(inbox1.EmailAddress);
await client.DeleteInboxAsync(inbox2.EmailAddress);
}

Here’s a complete example showing typical client usage:

using VaultSandbox.Client;
async Task Main(CancellationToken cancellationToken)
{
// Create client
var client = VaultSandboxClientBuilder.Create()
.WithBaseUrl(Environment.GetEnvironmentVariable("VAULTSANDBOX_URL"))
.WithApiKey(Environment.GetEnvironmentVariable("VAULTSANDBOX_API_KEY"))
.UseAutoDelivery()
.WithMaxRetries(5)
.Build();
try
{
// Verify API key
var isValid = await client.ValidateApiKeyAsync(cancellationToken);
if (!isValid)
{
throw new InvalidOperationException("Invalid API key");
}
// Get server info
var info = await client.GetServerInfoAsync(cancellationToken);
Console.WriteLine($"Connected to VaultSandbox (default TTL: {info.DefaultTtl}s)");
// Create inbox
var inbox = await client.CreateInboxAsync(cancellationToken: cancellationToken);
Console.WriteLine($"Created inbox: {inbox.EmailAddress}");
// Export for later use
await client.ExportInboxToFileAsync(inbox, "./inbox-backup.json", cancellationToken);
// Wait for email
var email = await inbox.WaitForEmailAsync(new WaitForEmailOptions
{
Timeout = TimeSpan.FromSeconds(30),
Subject = "Test"
}, cancellationToken);
Console.WriteLine($"Received: {email.Subject}");
// Clean up
await client.DeleteInboxAsync(inbox.EmailAddress, cancellationToken);
// Delete any other orphaned inboxes
var deleted = await client.DeleteAllInboxesAsync(cancellationToken);
Console.WriteLine($"Cleaned up {deleted} total inboxes");
}
finally
{
// Dispose the client
if (client is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
}
}