Inboxes
Inboxes are the core concept in VaultSandbox. Each inbox is an isolated, encrypted email destination with its own unique address and encryption keys.
What is an Inbox?
Section titled “What is an Inbox?”An inbox is a temporary email destination that:
- Has a unique email address (e.g.,
a1b2c3d4@mail.example.com) - Supports optional encryption (ML-KEM-768 keypair) based on server policy
- Expires automatically after a configurable time-to-live (TTL)
- Is isolated from other inboxes
- Stores emails in memory on the gateway
- Can optionally skip email authentication checks (SPF/DKIM/DMARC/PTR)
Creating Inboxes
Section titled “Creating Inboxes”Basic Creation
Section titled “Basic Creation”import com.vaultsandbox.client.VaultSandboxClient;import com.vaultsandbox.client.ClientConfig;import com.vaultsandbox.client.Inbox;
ClientConfig config = ClientConfig.builder() .apiKey("your-api-key") .baseUrl("https://gateway.example.com") .build();
VaultSandboxClient client = VaultSandboxClient.create(config);
Inbox inbox = client.createInbox();
System.out.println(inbox.getEmailAddress()); // "a1b2c3d4@mail.example.com"System.out.println(inbox.getHash()); // "Rr02MLnP7F0pRVC..."System.out.println(inbox.getExpiresAt()); // InstantWith Options
Section titled “With Options”import com.vaultsandbox.client.CreateInboxOptions;import java.time.Duration;
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(1)) .emailAddress("test@mail.example.com") .build());Note: Requesting a specific email address may fail if it’s already in use. The server will return an error.
With Email Auth Disabled
Section titled “With Email Auth Disabled”Disable SPF/DKIM/DMARC/PTR checks for this inbox:
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAuth(false) .build());
// All auth results will show "skipped" statusEmail email = inbox.waitForEmail();System.out.println(email.getAuthResults().getSpf().getResult()); // "skipped"With Encryption Options
Section titled “With Encryption Options”Request a specific encryption mode (when server policy allows):
// Request a plain (unencrypted) inboxInbox inbox = client.createInbox( CreateInboxOptions.builder() .encryption("plain") .build());
// Or use convenience methodInbox inbox = client.createInbox(CreateInboxOptions.plain());
// Request an encrypted inboxInbox inbox = client.createInbox( CreateInboxOptions.builder() .encryption("encrypted") .build());
// Or use convenience methodInbox inbox = client.createInbox(CreateInboxOptions.encrypted());Note: Encryption options depend on server policy. See Server Info for details.
Inbox Properties
Section titled “Inbox Properties”emailAddress
Section titled “emailAddress”Type: String
The full email address for this inbox.
System.out.println(inbox.getEmailAddress());// "a1b2c3d4@mail.example.com"Send emails to this address to have them appear in the inbox.
hash (inboxHash)
Section titled “hash (inboxHash)”Type: String
A unique cryptographic hash identifier for the inbox. Used internally for encryption and identification.
System.out.println(inbox.getHash());// "Rr02MLnP7F0pRVC6QdcpSIeyklqu3PDkYglvsfN7Oss"Note: This is not the same as the local part of the email address. The email address local part (e.g., a1b2c3d4 in a1b2c3d4@mail.example.com) is different from the inboxHash.
expiresAt
Section titled “expiresAt”Type: Instant
When the inbox will automatically expire and be deleted.
System.out.println(inbox.getExpiresAt());// 2024-01-16T12:00:00Z
// Check if inbox is expiring soonDuration untilExpiry = Duration.between(Instant.now(), inbox.getExpiresAt());System.out.printf("Expires in %.1f hours%n", untilExpiry.toHours());emailAuth
Section titled “emailAuth”Type: boolean
Whether email authentication checks (SPF/DKIM/DMARC/PTR) are enabled for this inbox.
System.out.println(inbox.isEmailAuth());// true (default) or false if disabledWhen emailAuth is false, all authentication results will have a skipped status.
encrypted
Section titled “encrypted”Type: boolean
Whether this inbox uses end-to-end encryption.
System.out.println(inbox.isEncrypted());// true (encrypted) or false (plain)Note: When encrypted is true, the inbox will have a serverSigPk property for signature verification. When false, serverSigPk will be null.
Inbox Lifecycle
Section titled “Inbox Lifecycle”┌─────────────────────────────────────────────────────────┐│ Inbox Lifecycle │└─────────────────────────────────────────────────────────┘
1. Creation client.createInbox() → Inbox object ↓ - Keypair generated client-side - Public key sent to server - Unique email address assigned - TTL timer starts
2. Active ↓ - Receive emails - List/read emails - Wait for emails - Monitor for new emails
3. Expiration (TTL reached) or Manual Deletion ↓ inbox.delete() or TTL expires - All emails deleted - Inbox address freed - Keypair destroyedWorking with Inboxes
Section titled “Working with Inboxes”Listing Emails
Section titled “Listing Emails”List<Email> emails = inbox.listEmails();
System.out.printf("%d emails in inbox%n", emails.size());for (Email email : emails) { System.out.printf("%s: %s%n", email.getFrom(), email.getSubject());}Getting a Specific Email
Section titled “Getting a Specific Email”Email email = inbox.getEmail("email-id-123");
System.out.println(email.getSubject());System.out.println(email.getText());Waiting for Emails
Section titled “Waiting for Emails”// Wait for any email (uses default timeout)Email email = inbox.waitForEmail();
// Wait with custom timeoutEmail email = inbox.waitForEmail(EmailFilter.any(), Duration.ofSeconds(30));
// Wait for specific emailEmail email = inbox.waitForEmail( EmailFilter.subjectContains("Password Reset"), Duration.ofSeconds(30));
// Wait with filter builderEmail email = inbox.waitForEmail( EmailFilter.builder() .subject("Welcome") .from("noreply@example.com") .build(), Duration.ofSeconds(30));Wait Methods vs Await Methods
Section titled “Wait Methods vs Await Methods”The waitForEmail methods throw TimeoutException if no email arrives:
try { Email email = inbox.waitForEmail(Duration.ofSeconds(10));} catch (TimeoutException e) { System.err.println("No email received within timeout");}The awaitEmail methods return null on timeout:
Email email = inbox.awaitEmail(Duration.ofSeconds(10));if (email == null) { System.err.println("No email received within timeout");}Waiting for Multiple Emails
Section titled “Waiting for Multiple Emails”// Wait for exactly 3 emailsList<Email> emails = inbox.waitForEmailCount(3, Duration.ofSeconds(30));
System.out.printf("Received %d emails%n", emails.size());Subscribing to New Emails
Section titled “Subscribing to New Emails”Subscription subscription = inbox.onNewEmail(email -> { System.out.println("New email: " + email.getSubject());});
// Later, unsubscribesubscription.unsubscribe();Deleting Emails
Section titled “Deleting Emails”// Delete specific email by IDinbox.deleteEmail("email-id-123");
// Or via email objectemail.delete();Deleting Inbox
Section titled “Deleting Inbox”// Delete inbox and all its emailsinbox.delete();Inbox Isolation
Section titled “Inbox Isolation”Each inbox is completely isolated:
Inbox inbox1 = client.createInbox();Inbox inbox2 = client.createInbox();
// inbox1 cannot access inbox2's emails// inbox2 cannot access inbox1's emails
// Each has its own:// - Email address// - Encryption keys// - Email storage// - Expiration timeTime-to-Live (TTL)
Section titled “Time-to-Live (TTL)”Inboxes automatically expire after their TTL.
Default TTL
Section titled “Default TTL”// Uses server's default TTL (typically 24 hours)Inbox inbox = client.createInbox();Custom TTL
Section titled “Custom TTL”// Expire after 1 hourInbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(1)) .build());
// Expire after 10 minutes (useful for quick tests)Inbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofMinutes(10)) .build());
// Expire after 7 daysInbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofDays(7)) .build());Checking Expiration
Section titled “Checking Expiration”Duration timeLeft = Duration.between(Instant.now(), inbox.getExpiresAt());long minutesLeft = timeLeft.toMinutes();
if (minutesLeft < 5) { System.err.println("Inbox expiring soon!");}Import and Export
Section titled “Import and Export”Inboxes can be exported and imported for:
- Test reproducibility
- Sharing between environments
- Backup and restore
Export
Section titled “Export”// Export via inboxExportedInbox exported = inbox.export();
// Or via clientExportedInbox exported = client.exportInbox(inbox);
// Export to fileclient.exportInboxToFile(inbox, Path.of("inbox.json"));Import
Section titled “Import”// Import from ExportedInbox objectInbox inbox = client.importInbox(exported);
// Import from fileInbox inbox = client.importInboxFromFile(Path.of("inbox.json"));
// Inbox restored with all encryption keysSystem.out.println(inbox.getEmailAddress());Security Warning: Exported data contains private keys. Treat as sensitive and handle securely.
Best Practices
Section titled “Best Practices”CI/CD Pipelines
Section titled “CI/CD Pipelines”Short TTL for fast cleanup:
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(1)) .build());Always clean up:
Inbox inbox = null;try { inbox = client.createInbox(); // Run tests} finally { if (inbox != null) { inbox.delete(); }}Manual Testing
Section titled “Manual Testing”Longer TTL for convenience:
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(24)) .build());Export for reuse:
// Export after creatingclient.exportInboxToFile(inbox, Path.of("test-inbox.json"));
// Reuse in later sessionsInbox inbox = client.importInboxFromFile(Path.of("test-inbox.json"));Common Patterns
Section titled “Common Patterns”Dedicated Test Inbox (JUnit 5)
Section titled “Dedicated Test Inbox (JUnit 5)”class EmailTest { private static VaultSandboxClient client; private Inbox inbox;
@BeforeAll static void initClient() { ClientConfig config = ClientConfig.builder() .apiKey(System.getenv("VAULTSANDBOX_API_KEY")) .baseUrl(System.getenv("VAULTSANDBOX_URL")) .build(); client = VaultSandboxClient.create(config); }
@BeforeEach void setUp() { inbox = client.createInbox(); }
@AfterEach void tearDown() { if (inbox != null) { inbox.delete(); } }
@Test void shouldReceivePasswordResetEmail() { triggerPasswordReset(inbox.getEmailAddress());
Email email = inbox.waitForEmail( EmailFilter.subjectContains("Password Reset"), Duration.ofSeconds(10) );
assertThat(email.getSubject()).contains("Password Reset"); }}Multiple Inboxes
Section titled “Multiple Inboxes”Inbox user1Inbox = client.createInbox();Inbox user2Inbox = client.createInbox();Inbox adminInbox = client.createInbox();
// Each inbox receives emails independentlysendWelcomeEmail(user1Inbox.getEmailAddress());sendWelcomeEmail(user2Inbox.getEmailAddress());sendAdminReport(adminInbox.getEmailAddress());Creating Multiple Inboxes
Section titled “Creating Multiple Inboxes”List<Inbox> inboxes = IntStream.range(0, 5) .mapToObj(i -> client.createInbox()) .collect(Collectors.toList());
// Clean up allinboxes.forEach(Inbox::delete);Inbox Pool
Section titled “Inbox Pool”class InboxPool implements Closeable { private final VaultSandboxClient client; private final Queue<Inbox> pool = new ConcurrentLinkedQueue<>(); private final int size;
public InboxPool(VaultSandboxClient client, int size) { this.client = client; this.size = size; }
public void initialize() { for (int i = 0; i < size; i++) { pool.add(client.createInbox()); } }
public Inbox acquire() { Inbox inbox = pool.poll(); if (inbox == null) { return client.createInbox(); } return inbox; }
public void release(Inbox inbox) { pool.add(inbox); }
@Override public void close() { pool.forEach(Inbox::delete); }}Troubleshooting
Section titled “Troubleshooting”Inbox Not Receiving Emails
Section titled “Inbox Not Receiving Emails”Check:
- Email is sent to correct address
- Inbox hasn’t expired
- DNS/MX records configured correctly
- SMTP connection successful
// Verify inbox still existstry { List<Email> emails = inbox.listEmails(); // Will error if inbox expired System.out.println("Inbox is active");} catch (InboxNotFoundException e) { System.err.println("Inbox has expired");}Inbox Already Exists Error
Section titled “Inbox Already Exists Error”When requesting a specific email address:
try { Inbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAddress("test@mail.example.com") .build() );} catch (InboxAlreadyExistsException e) { // Address already in use, generate random instead Inbox inbox = client.createInbox();}Inbox Expired
Section titled “Inbox Expired”try { List<Email> emails = inbox.listEmails();} catch (InboxNotFoundException e) { System.err.println("Inbox has expired"); // Create new inbox Inbox newInbox = client.createInbox();}Invalid Import Data
Section titled “Invalid Import Data”try { Inbox inbox = client.importInboxFromFile(Path.of("old-inbox.json"));} catch (InvalidImportDataException e) { System.err.println("Import failed: " + e.getMessage()); // Common causes: // - Inbox has expired // - Invalid key format // - Missing required fields}Checking Server Encryption Policy
Section titled “Checking Server Encryption Policy”The server’s encryption policy determines how inbox encryption can be configured:
ServerInfo info = client.getServerInfo();String policy = info.getEncryptionPolicy();
System.out.println("Encryption policy: " + policy);System.out.println("Can override: " + info.canOverrideEncryption());System.out.println("Default encrypted: " + info.isDefaultEncrypted());Encryption Policies
Section titled “Encryption Policies”| Policy | Default Behavior | Can Override? |
|---|---|---|
always | Encrypted | No - all inboxes are always encrypted |
enabled | Encrypted | Yes - can request plain |
disabled | Plain | Yes - can request encrypted |
never | Plain | No - all inboxes are always plain |
Example: Conditional Inbox Creation
Section titled “Example: Conditional Inbox Creation”ServerInfo info = client.getServerInfo();
CreateInboxOptions.Builder options = CreateInboxOptions.builder();
if (info.canOverrideEncryption() && !info.isDefaultEncrypted()) { // Server allows overrides and default is plain - request encrypted options.encryption("encrypted");}
Inbox inbox = client.createInbox(options.build());System.out.println("Inbox encrypted: " + inbox.isEncrypted());Next Steps
Section titled “Next Steps”- Email Objects - Learn about email structure
- Managing Inboxes - Common inbox operations
- Import/Export - Advanced inbox persistence
- API Reference: Inbox - Complete API documentation