VaultSandboxClient API
The VaultSandboxClient is the main entry point for interacting with the VaultSandbox Gateway. It handles authentication, inbox creation, and provides utility methods for managing inboxes.
Constructor
Section titled “Constructor”VaultSandboxClient( api_key: str, *, base_url: str = "https://smtp.vaultsandbox.com", timeout: int = 30000, max_retries: int = 3, retry_delay: int = 1000, retry_on_status_codes: tuple[int, ...] | None = None, strategy: DeliveryStrategyType = DeliveryStrategyType.AUTO, polling_interval: int = 2000, polling_max_backoff: int = 30000, sse_reconnect_interval: int = 5000, sse_max_reconnect_attempts: int = 10,)Creates a new VaultSandbox client instance.
Parameters
Section titled “Parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
api_key | str | Yes | - | Your API authentication key |
base_url | str | No | https://smtp.vaultsandbox.com | Gateway URL |
timeout | int | No | 30000 | HTTP request timeout in milliseconds |
max_retries | int | No | 3 | Maximum retry attempts for HTTP requests |
retry_delay | int | No | 1000 | Base delay in milliseconds between retries |
retry_on_status_codes | tuple[int, ...] | No | (408, 429, 500, 502, 503, 504) | HTTP status codes that trigger a retry |
strategy | DeliveryStrategyType | No | AUTO | Email delivery strategy |
polling_interval | int | No | 2000 | Polling interval in milliseconds |
polling_max_backoff | int | No | 30000 | Maximum backoff delay in milliseconds |
sse_reconnect_interval | int | No | 5000 | Initial delay before SSE reconnection (ms) |
sse_max_reconnect_attempts | int | No | 10 | Maximum SSE reconnection attempts |
Example
Section titled “Example”import osfrom vaultsandbox import VaultSandboxClient, DeliveryStrategyType
async with VaultSandboxClient( api_key=os.environ["VAULTSANDBOX_API_KEY"], base_url="https://smtp.vaultsandbox.com", strategy=DeliveryStrategyType.AUTO, max_retries=5, retry_delay=2000,) as client: inbox = await client.create_inbox()Context Manager
Section titled “Context Manager”The recommended way to use the client is with Python’s async with context manager, which ensures proper cleanup of resources:
async with VaultSandboxClient(api_key="your-api-key") as client: inbox = await client.create_inbox() email = await inbox.wait_for_email() print(f"Received: {email.subject}")Methods
Section titled “Methods”create_inbox()
Section titled “create_inbox()”Creates a new email inbox with automatic key generation and encryption setup.
async def create_inbox( self, options: CreateInboxOptions | None = None,) -> InboxParameters
Section titled “Parameters”options(optional): Configuration for the inbox
@dataclassclass CreateInboxOptions: ttl: int | None = None email_address: str | None = None| Property | Type | Description |
|---|---|---|
ttl | int | None | Time-to-live for the inbox in seconds (min: 60, max: 604800, default: server’s defaultTtl) |
email_address | str | None | Request a specific email address (max 254 chars, e.g., [email protected]) |
Returns
Section titled “Returns”Inbox - The created inbox instance
Example
Section titled “Example”from vaultsandbox import CreateInboxOptions
# Create inbox with default settingsinbox = await client.create_inbox()print(inbox.email_address)
# Create inbox with custom TTL (1 hour)inbox = await client.create_inbox(CreateInboxOptions(ttl=3600))
# Request specific email addressinbox = await client.create_inbox()Errors
Section titled “Errors”ApiError- API-level error (invalid request, permission denied)NetworkError- Network connection failureInboxAlreadyExistsError- Requested email address is already in use
delete_all_inboxes()
Section titled “delete_all_inboxes()”Deletes all inboxes associated with the current API key. Useful for cleanup in test environments.
async def delete_all_inboxes(self) -> intReturns
Section titled “Returns”int - Number of inboxes deleted
Example
Section titled “Example”deleted = await client.delete_all_inboxes()print(f"Deleted {deleted} inboxes")Best Practice
Section titled “Best Practice”Use this in test cleanup to avoid orphaned inboxes:
@pytest.fixtureasync def client(): async with VaultSandboxClient(api_key=api_key) as client: yield client # Clean up all inboxes after tests deleted = await client.delete_all_inboxes() if deleted > 0: print(f"Cleaned up {deleted} orphaned inboxes")get_server_info()
Section titled “get_server_info()”Retrieves information about the VaultSandbox Gateway server.
async def get_server_info(self) -> ServerInfoReturns
Section titled “Returns”ServerInfo - Server information object
@dataclassclass ServerInfo: server_sig_pk: str algs: dict[str, str] context: str max_ttl: int default_ttl: int sse_console: bool allowed_domains: list[str]| Property | Type | Description |
|---|---|---|
server_sig_pk | str | Base64URL-encoded server signing public key for ML-DSA-65 |
algs | dict[str, str] | Cryptographic algorithms supported by the server |
context | str | Context string for the encryption scheme |
max_ttl | int | Maximum time-to-live for inboxes in seconds |
default_ttl | int | Default time-to-live for inboxes in seconds |
sse_console | bool | Whether the server SSE console is enabled |
allowed_domains | list[str] | List of domains allowed for inbox creation |
Example
Section titled “Example”info = await client.get_server_info()print(f"Encryption: {info.algs['kem']}")print(f"Max TTL: {info.max_ttl}s, Default TTL: {info.default_ttl}s")print(f"Allowed domains: {', '.join(info.allowed_domains)}")check_key()
Section titled “check_key()”Validates the API key with the server.
async def check_key(self) -> boolReturns
Section titled “Returns”bool - True if the API key is valid
Example
Section titled “Example”is_valid = await client.check_key()if not is_valid: raise ValueError("Invalid API key")Useful for verifying configuration before running tests:
import pytestimport osfrom vaultsandbox import VaultSandboxClient
@pytest.fixture(scope="session")async def validated_client(): async with VaultSandboxClient( api_key=os.environ["VAULTSANDBOX_API_KEY"] ) as client: is_valid = await client.check_key() if not is_valid: pytest.fail("VaultSandbox API key is invalid") yield clientmonitor_inboxes()
Section titled “monitor_inboxes()”Monitors multiple inboxes simultaneously and provides callbacks when new emails arrive.
def monitor_inboxes(self, inboxes: list[Inbox]) -> InboxMonitorParameters
Section titled “Parameters”inboxes: List of inbox instances to monitor
Returns
Section titled “Returns”InboxMonitor - Monitor instance for inbox monitoring
Example
Section titled “Example”inbox1 = await client.create_inbox()inbox2 = await client.create_inbox()
monitor = client.monitor_inboxes([inbox1, inbox2])
@monitor.on_emailasync def handle_email(inbox: Inbox, email: Email): print(f"New email in {inbox.email_address}: {email.subject}")
await monitor.start()
# Later, stop monitoringawait monitor.unsubscribe()See InboxMonitor API for more details.
export_inbox()
Section titled “export_inbox()”Exports an inbox’s data and encryption keys for backup or sharing. The exported data includes sensitive key material and should be treated as confidential.
def export_inbox(self, inbox_or_email: Inbox | str) -> ExportedInboxParameters
Section titled “Parameters”inbox_or_email: Inbox instance or email address string to export
Returns
Section titled “Returns”ExportedInbox - Serializable inbox data including keys
@dataclassclass ExportedInbox: version: int # Export format version (always 1) email_address: str expires_at: str inbox_hash: str server_sig_pk: str # Base64url-encoded secret_key: str # Base64url-encoded (SENSITIVE!) exported_at: strNote: The public key is derived from the secret key during import.
Example
Section titled “Example”import json
inbox = await client.create_inbox()exported_data = client.export_inbox(inbox)
# Save for later use (treat as sensitive!)print(json.dumps(vars(exported_data), indent=2))Security Warning
Section titled “Security Warning”Exported data contains private encryption keys. Store securely and never commit to version control.
import_inbox()
Section titled “import_inbox()”Imports a previously exported inbox, restoring all data and encryption keys.
async def import_inbox(self, data: ExportedInbox) -> InboxParameters
Section titled “Parameters”data: Previously exported inbox data
Returns
Section titled “Returns”Inbox - The imported inbox instance
Example
Section titled “Example”import jsonfrom vaultsandbox import ExportedInbox
# Load exported datawith open("inbox-backup.json") as f: data = json.load(f)
exported = ExportedInbox( version=data["version"], email_address=data["emailAddress"], expires_at=data["expiresAt"], inbox_hash=data["inboxHash"], server_sig_pk=data["serverSigPk"], secret_key=data["secretKey"], exported_at=data.get("exportedAt", ""),)
inbox = await client.import_inbox(exported)print(f"Imported inbox: {inbox.email_address}")
# Use inbox normallyemails = await inbox.list_emails()Errors
Section titled “Errors”UnsupportedVersionError- Export version is not supportedInboxAlreadyExistsError- Inbox is already imported in this clientInvalidImportDataError- Import data is invalid or corruptedApiError- Server rejected the import (inbox may not exist)
export_inbox_to_file()
Section titled “export_inbox_to_file()”Exports an inbox to a JSON file on disk.
async def export_inbox_to_file( self, inbox_or_email: Inbox | str, file_path: str | Path,) -> NoneParameters
Section titled “Parameters”inbox_or_email: Inbox instance or email address string to exportfile_path: Path where the JSON file will be written
Example
Section titled “Example”inbox = await client.create_inbox()
# Export to fileawait client.export_inbox_to_file(inbox, "./backup/inbox.json")
print("Inbox exported to ./backup/inbox.json")import_inbox_from_file()
Section titled “import_inbox_from_file()”Imports an inbox from a JSON file.
async def import_inbox_from_file(self, file_path: str | Path) -> InboxParameters
Section titled “Parameters”file_path: Path to the exported inbox JSON file
Returns
Section titled “Returns”Inbox - The imported inbox instance
Example
Section titled “Example”# Import from fileinbox = await client.import_inbox_from_file("./backup/inbox.json")
print(f"Imported inbox: {inbox.email_address}")
# Monitor for new emailssubscription = await inbox.on_new_email( lambda email: print(f"New email: {email.subject}"))Use Cases
Section titled “Use Cases”- Test reproducibility across runs
- Sharing inboxes between environments
- Manual testing workflows
- Debugging production issues
close()
Section titled “close()”Closes the client, terminates any active SSE or polling connections, and cleans up resources.
async def close(self) -> NoneExample
Section titled “Example”client = VaultSandboxClient(api_key=api_key)
try: inbox = await client.create_inbox() # Use inbox...finally: await client.close()Best Practice
Section titled “Best Practice”Always close the client when done, especially in long-running processes. The recommended approach is to use the context manager:
async with VaultSandboxClient(api_key=api_key) as client: inbox = await client.create_inbox() # Use inbox...# Client automatically closedOr with pytest fixtures:
import pytestfrom vaultsandbox import VaultSandboxClient
@pytest.fixtureasync def client(): async with VaultSandboxClient(api_key=api_key) as client: yield clientInboxMonitor
Section titled “InboxMonitor”The InboxMonitor class allows you to monitor multiple inboxes simultaneously.
Creating a Monitor
Section titled “Creating a Monitor”inbox1 = await client.create_inbox()inbox2 = await client.create_inbox()
monitor = client.monitor_inboxes([inbox1, inbox2])Methods
Section titled “Methods”on_email()
Section titled “on_email()”Register a callback for new emails. Can be used as a decorator.
def on_email(self, callback: Callable[[Inbox, Email], Any]) -> InboxMonitorParameters
Section titled “Parameters”callback: Function to call when new emails arrive. Receives(inbox, email)as arguments.
Returns
Section titled “Returns”InboxMonitor - Self for method chaining
Example
Section titled “Example”# Using as a decorator@monitor.on_emailasync def handle_email(inbox: Inbox, email: Email): print(f"Email received in {inbox.email_address}") print(f"Subject: {email.subject}")
# Or using method chainingmonitor.on_email(handle_email).on_email(another_handler)start()
Section titled “start()”Start monitoring inboxes.
async def start(self) -> InboxMonitorReturns
Section titled “Returns”InboxMonitor - Self for method chaining
Example
Section titled “Example”await monitor.start()unsubscribe()
Section titled “unsubscribe()”Stops monitoring all inboxes and cleans up resources.
async def unsubscribe(self) -> NoneExample
Section titled “Example”monitor = client.monitor_inboxes([inbox1, inbox2])
# Use monitor...
# Stop monitoringawait monitor.unsubscribe()Complete Example
Section titled “Complete Example”import asynciofrom vaultsandbox import VaultSandboxClient, Inbox, Email
async def monitor_multiple_inboxes(): async with VaultSandboxClient(api_key=api_key) as client: # Create multiple inboxes inbox1 = await client.create_inbox() inbox2 = await client.create_inbox()
print(f"Inbox 1: {inbox1.email_address}") print(f"Inbox 2: {inbox2.email_address}")
# Monitor both inboxes monitor = client.monitor_inboxes([inbox1, inbox2])
@monitor.on_email async def handle_email(inbox: Inbox, email: Email): print(f"\nNew email in {inbox.email_address}:") print(f" Subject: {email.subject}") print(f" From: {email.from_address}")
await monitor.start()
# Wait for emails to arrive... await asyncio.sleep(60)
# Clean up await monitor.unsubscribe() await inbox1.delete() await inbox2.delete()
asyncio.run(monitor_multiple_inboxes())Complete Example
Section titled “Complete Example”Here’s a complete example showing typical client usage:
import asyncioimport osfrom vaultsandbox import VaultSandboxClient, WaitForEmailOptionsimport re
async def main(): # Create client async with VaultSandboxClient( api_key=os.environ["VAULTSANDBOX_API_KEY"], max_retries=5, ) as client: # Verify API key is_valid = await client.check_key() if not is_valid: raise ValueError("Invalid API key")
# Get server info info = await client.get_server_info() print(f"Connected to VaultSandbox (default TTL: {info.default_ttl}s)")
# Create inbox inbox = await client.create_inbox() print(f"Created inbox: {inbox.email_address}")
# Export for later use await client.export_inbox_to_file(inbox, "./inbox-backup.json")
# Wait for email email = await inbox.wait_for_email( WaitForEmailOptions( timeout=30000, subject=re.compile(r"Test"), ) )
print(f"Received: {email.subject}")
# Clean up await inbox.delete()
# Delete any other orphaned inboxes deleted = await client.delete_all_inboxes() print(f"Cleaned up {deleted} total inboxes")
asyncio.run(main())Next Steps
Section titled “Next Steps”- Inbox API Reference - Learn about inbox methods
- Email API Reference - Work with email objects
- Error Handling - Handle errors gracefully
- Import/Export Guide - Advanced import/export usage