Managing Inboxes
This guide covers common inbox operations including creation, email management, and cleanup patterns for testing.
Creating Inboxes
Section titled “Creating Inboxes”Basic Creation
Section titled “Basic Creation”ClientConfig config = ClientConfig.builder() .apiKey(apiKey) .baseUrl(baseUrl) .build();VaultSandboxClient client = VaultSandboxClient.create(config);Inbox inbox = client.createInbox();
System.out.println("Send emails to: " + inbox.getEmailAddress());System.out.println("Expires at: " + inbox.getExpiresAt());With Custom TTL
Section titled “With Custom TTL”Inbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(2)) .build());With Specific Domain or Address
Section titled “With Specific Domain or Address”// Request specific domainInbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAddress("yourdomain.com") .build());
// Request specific full addressInbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAddress("test-user@yourdomain.com") .build());Multiple Options
Section titled “Multiple Options”Inbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAddress("testing@yourdomain.com") .ttl(Duration.ofMinutes(30)) .build());With Email Auth Disabled
Section titled “With Email Auth Disabled”Skip SPF/DKIM/DMARC/PTR checks for faster processing or when using test SMTP servers:
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .emailAuth(false) .build());
// All auth results will show "skipped" statusSystem.out.println("Email auth: " + inbox.isEmailAuth()); // falseWith Spam Analysis
Section titled “With Spam Analysis”Enable Rspamd spam analysis for incoming emails:
Inbox inbox = client.createInbox( CreateInboxOptions.builder() .spamAnalysis(true) .build());
// Check spam analysis statusSystem.out.println("Spam analysis: " + inbox.isSpamAnalysis()); // trueIf not specified, inboxes use the server’s default setting (VSB_SPAM_ANALYSIS_INBOX_DEFAULT).
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());
// Check encryption statusSystem.out.println("Encrypted: " + inbox.isEncrypted()); // falseChecking Server Encryption Policy
Section titled “Checking Server Encryption Policy”ServerInfo info = client.getServerInfo();
System.out.println("Policy: " + info.getEncryptionPolicy());System.out.println("Can override: " + info.canOverrideEncryption());System.out.println("Default encrypted: " + info.isDefaultEncrypted());
// Only request plain if server allows overridesif (info.canOverrideEncryption()) { Inbox inbox = client.createInbox(CreateInboxOptions.plain());}Inbox Properties
Section titled “Inbox Properties”| Property | Type | Description |
|---|---|---|
emailAddress | String | The inbox email address |
expiresAt | Instant | When the inbox expires |
emailAuth | boolean | Whether email authentication checks are enabled |
spamAnalysis | boolean | Whether spam analysis is enabled for this inbox |
encrypted | boolean | Whether this inbox uses end-to-end encryption |
Inbox inbox = client.createInbox();
String address = inbox.getEmailAddress(); // "abc123@vaultsandbox.com"Instant expires = inbox.getExpiresAt(); // 2024-01-15T12:00:00Zboolean auth = inbox.isEmailAuth(); // true (default)boolean spam = inbox.isSpamAnalysis(); // depends on server defaultboolean encrypted = inbox.isEncrypted(); // depends on server policyListing Emails
Section titled “Listing Emails”Get All Emails
Section titled “Get All Emails”List<Email> emails = inbox.listEmails();
for (Email email : emails) { System.out.println("From: " + email.getFrom()); System.out.println("Subject: " + email.getSubject()); System.out.println("Received: " + email.getReceivedAt());}With Stream API
Section titled “With Stream API”inbox.listEmails().stream() .filter(e -> e.getSubject().contains("Important")) .forEach(this::processEmail);Filtering Emails
Section titled “Filtering Emails”Using EmailFilter with Streams
Section titled “Using EmailFilter with Streams”// Filter by subjectList<Email> filtered = inbox.listEmails().stream() .filter(e -> e.getSubject().contains("Welcome")) .collect(Collectors.toList());
// Filter by senderList<Email> fromSupport = inbox.listEmails().stream() .filter(e -> e.getFrom().contains("support@")) .collect(Collectors.toList());Using EmailFilter Predicates
Section titled “Using EmailFilter Predicates”// Create reusable filtersEmailFilter welcomeFilter = EmailFilter.subjectContains("Welcome");EmailFilter supportFilter = EmailFilter.from("support@");
// Combine filtersEmailFilter combined = welcomeFilter.and(supportFilter);
// Apply to listList<Email> matching = inbox.listEmails().stream() .filter(combined::matches) .collect(Collectors.toList());Custom Predicates
Section titled “Custom Predicates”// Filter by attachment countList<Email> withAttachments = inbox.listEmails().stream() .filter(e -> !e.getAttachments().isEmpty()) .collect(Collectors.toList());
// Filter by multiple criteriaList<Email> recent = inbox.listEmails().stream() .filter(e -> e.getReceivedAt().isAfter(Instant.now().minus(Duration.ofMinutes(5)))) .filter(e -> !e.isRead()) .collect(Collectors.toList());Sorting Emails
Section titled “Sorting Emails”By Received Date
Section titled “By Received Date”// Newest firstList<Email> sorted = inbox.listEmails().stream() .sorted(Comparator.comparing(Email::getReceivedAt).reversed()) .collect(Collectors.toList());
// Oldest firstList<Email> oldest = inbox.listEmails().stream() .sorted(Comparator.comparing(Email::getReceivedAt)) .collect(Collectors.toList());By Subject
Section titled “By Subject”List<Email> bySubject = inbox.listEmails().stream() .sorted(Comparator.comparing(Email::getSubject, Comparator.nullsLast(String::compareToIgnoreCase))) .collect(Collectors.toList());Getting Specific Emails
Section titled “Getting Specific Emails”Email email = inbox.getEmail(emailId);First Email
Section titled “First Email”Email first = inbox.listEmails().stream() .findFirst() .orElseThrow(() -> new AssertionError("No emails found"));Latest Email
Section titled “Latest Email”Email latest = inbox.listEmails().stream() .max(Comparator.comparing(Email::getReceivedAt)) .orElseThrow(() -> new AssertionError("No emails found"));First Matching Filter
Section titled “First Matching Filter”Email welcome = inbox.listEmails().stream() .filter(e -> e.getSubject().contains("Welcome")) .findFirst() .orElseThrow(() -> new AssertionError("Welcome email not found"));Managing Email State
Section titled “Managing Email State”Mark as Read
Section titled “Mark as Read”// Via inboxinbox.markEmailAsRead(emailId);
// Via email objectemail.markAsRead();Check Read Status
Section titled “Check Read Status”List<Email> unread = inbox.listEmails().stream() .filter(e -> !e.isRead()) .collect(Collectors.toList());
System.out.println("Unread emails: " + unread.size());Deleting Emails
Section titled “Deleting Emails”Single Email
Section titled “Single Email”// By IDinbox.deleteEmail(emailId);
// Via email objectemail.delete();Multiple Emails
Section titled “Multiple Emails”// Delete all read emailsinbox.listEmails().stream() .filter(Email::isRead) .forEach(Email::delete);By Criteria
Section titled “By Criteria”// Delete old emailsInstant cutoff = Instant.now().minus(Duration.ofHours(1));
inbox.listEmails().stream() .filter(e -> e.getReceivedAt().isBefore(cutoff)) .forEach(Email::delete);All Emails in Inbox
Section titled “All Emails in Inbox”inbox.listEmails().forEach(Email::delete);Deleting Inboxes
Section titled “Deleting Inboxes”Single Inbox
Section titled “Single Inbox”// Via clientclient.deleteInbox(inbox.getEmailAddress());
// Via inbox objectinbox.delete();All Inboxes
Section titled “All Inboxes”int deletedCount = client.deleteAllInboxes();System.out.println("Deleted " + deletedCount + " inbox(es)");Bulk Operations
Section titled “Bulk Operations”Create Multiple Inboxes
Section titled “Create Multiple Inboxes”List<Inbox> inboxes = IntStream.range(0, 10) .mapToObj(i -> client.createInbox()) .collect(Collectors.toList());
// Use inboxes...
// Clean upinboxes.forEach(Inbox::delete);Parallel Processing
Section titled “Parallel Processing”List<Inbox> inboxes = IntStream.range(0, 5) .mapToObj(i -> client.createInbox()) .collect(Collectors.toList());
// Process emails in parallelinboxes.parallelStream() .flatMap(inbox -> inbox.listEmails().stream()) .filter(e -> e.getSubject().contains("Alert")) .forEach(this::processAlert);Testing Patterns
Section titled “Testing Patterns”JUnit 5 Setup/Teardown
Section titled “JUnit 5 Setup/Teardown”class EmailTest { private VaultSandboxClient client; private Inbox inbox;
@BeforeEach void setUp() { ClientConfig config = ClientConfig.builder() .apiKey(System.getenv("VAULTSANDBOX_API_KEY")) .baseUrl(System.getenv("VAULTSANDBOX_URL")) .build(); client = VaultSandboxClient.create(config); inbox = client.createInbox(); }
@AfterEach void tearDown() { if (inbox != null) { try { inbox.delete(); } catch (Exception ignored) {} } if (client != null) { client.close(); } }
@Test void shouldReceiveWelcomeEmail() { // Trigger email signUpUser(inbox.getEmailAddress());
// Wait and verify Email email = inbox.waitForEmail( EmailFilter.subjectContains("Welcome"), Duration.ofSeconds(30) );
assertThat(email.getFrom()).isEqualTo("noreply@example.com"); }}Try-With-Resources Pattern
Section titled “Try-With-Resources Pattern”@Testvoid shouldProcessEmails() { ClientConfig config = ClientConfig.builder() .apiKey(apiKey) .baseUrl(baseUrl) .build(); try (VaultSandboxClient client = VaultSandboxClient.create(config)) { Inbox inbox = client.createInbox();
try { // Trigger and receive emails sendTestEmail(inbox.getEmailAddress()); Email email = inbox.waitForEmail(Duration.ofSeconds(30)); assertThat(email).isNotNull(); } finally { inbox.delete(); } }}Shared Inbox Pattern
Section titled “Shared Inbox Pattern”For tests that share a single inbox:
@TestInstance(TestInstance.Lifecycle.PER_CLASS)class SharedInboxTest { private VaultSandboxClient client; private Inbox inbox;
@BeforeAll void setUpClass() { ClientConfig config = ClientConfig.builder() .apiKey(System.getenv("VAULTSANDBOX_API_KEY")) .baseUrl(System.getenv("VAULTSANDBOX_URL")) .build(); client = VaultSandboxClient.create(config); inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofHours(1)) .build() ); }
@AfterAll void tearDownClass() { if (client != null) { client.deleteAllInboxes(); client.close(); } }
@BeforeEach void clearEmails() { // Clear emails between tests inbox.listEmails().forEach(Email::delete); }
@Test void testOne() { // Uses shared inbox }
@Test void testTwo() { // Uses same shared inbox }}Inbox Pool Pattern
Section titled “Inbox Pool Pattern”For high-throughput testing:
class InboxPool { private final Queue<Inbox> available = new ConcurrentLinkedQueue<>(); private final VaultSandboxClient client;
public InboxPool(VaultSandboxClient client) { this.client = client; }
public Inbox acquire() { Inbox inbox = available.poll(); if (inbox != null) { return inbox; } return client.createInbox(); }
public void release(Inbox inbox) { // Clear emails and return to pool try { inbox.listEmails().forEach(Email::delete); available.offer(inbox); } catch (Exception e) { // Inbox may have expired, don't return to pool } }
public void shutdown() { Inbox inbox; while ((inbox = available.poll()) != null) { try { inbox.delete(); } catch (Exception ignored) {} } }}Usage:
class PooledInboxTest { private static InboxPool pool; private Inbox inbox;
@BeforeAll static void setUpPool() { ClientConfig config = ClientConfig.builder() .apiKey(apiKey) .baseUrl(baseUrl) .build(); VaultSandboxClient client = VaultSandboxClient.create(config); pool = new InboxPool(client); }
@AfterAll static void tearDownPool() { pool.shutdown(); }
@BeforeEach void acquireInbox() { inbox = pool.acquire(); }
@AfterEach void releaseInbox() { pool.release(inbox); }
@Test void testWithPooledInbox() { // Use inbox... }}Test Base Class
Section titled “Test Base Class”abstract class EmailTestBase { protected VaultSandboxClient client; protected Inbox inbox;
@BeforeEach void setUpInbox() { ClientConfig config = ClientConfig.builder() .apiKey(System.getenv("VAULTSANDBOX_API_KEY")) .baseUrl(System.getenv("VAULTSANDBOX_URL")) .build(); client = VaultSandboxClient.create(config); inbox = client.createInbox(); }
@AfterEach void tearDownInbox() { if (inbox != null) { try { inbox.delete(); } catch (Exception ignored) {} } if (client != null) { client.close(); } }
protected Email waitForEmail(String subjectContains) { return inbox.waitForEmail( EmailFilter.subjectContains(subjectContains), Duration.ofSeconds(30) ); }}
class WelcomeEmailTest extends EmailTestBase { @Test void shouldSendWelcomeEmail() { signUp(inbox.getEmailAddress()); Email email = waitForEmail("Welcome"); assertThat(email).isNotNull(); }}Error Handling
Section titled “Error Handling”Common Exceptions
Section titled “Common Exceptions”try { Inbox inbox = client.createInbox(); Email email = inbox.waitForEmail(Duration.ofSeconds(10));} catch (ApiException e) { System.err.println("API error: " + e.getStatusCode() + " - " + e.getMessage());} catch (NetworkException e) { System.err.println("Network error: " + e.getMessage());} catch (TimeoutException e) { System.err.println("Timeout waiting for email");} catch (VaultSandboxException e) { System.err.println("General error: " + e.getMessage());}Inbox Not Found
Section titled “Inbox Not Found”try { client.deleteInbox("nonexistent@vaultsandbox.com");} catch (InboxNotFoundException e) { System.err.println("Inbox does not exist: " + e.getMessage());}Graceful Cleanup
Section titled “Graceful Cleanup”void cleanupSafely(Inbox inbox) { if (inbox == null) return;
try { inbox.delete(); } catch (InboxNotFoundException e) { // Already deleted, ignore } catch (Exception e) { System.err.println("Failed to delete inbox: " + e.getMessage()); }}Optional Email Handling
Section titled “Optional Email Handling”Use awaitEmail() instead of waitForEmail() when an email might not arrive and you don’t want an exception on timeout.
Check for Optional Email
Section titled “Check for Optional Email”// Returns null on timeout instead of throwing TimeoutExceptionEmail notification = inbox.awaitEmail( EmailFilter.subjectContains("Optional Notification"), Duration.ofSeconds(5));
if (notification != null) { processNotification(notification);} else { // No notification - this is acceptable log.info("No optional notification received");}Conditional Processing
Section titled “Conditional Processing”@Testvoid shouldHandleOptionalConfirmationEmail() { // Trigger action that may or may not send email performAction(inbox.getEmailAddress());
// Wait for required email Email required = inbox.waitForEmail( EmailFilter.subjectContains("Action Complete"), Duration.ofSeconds(30) ); assertThat(required).isNotNull();
// Check for optional follow-up (no exception if missing) Email followUp = inbox.awaitEmail( EmailFilter.subjectContains("Additional Info"), Duration.ofSeconds(5) );
if (followUp != null) { // Verify follow-up content if present assertThat(followUp.getText()).contains("extra details"); }}Difference from waitForEmail()
Section titled “Difference from waitForEmail()”| Method | On Timeout | Use Case |
|---|---|---|
waitForEmail() | Throws TimeoutException | Required emails that must arrive |
awaitEmail() | Returns null | Optional emails that may not come |
Retrieving Inboxes
Section titled “Retrieving Inboxes”From Client Registry
Section titled “From Client Registry”// Create inboxInbox inbox = client.createInbox();String address = inbox.getEmailAddress();
// Later, retrieve from same client instanceInbox sameInbox = client.getInbox(address);Best Practices
Section titled “Best Practices”- Always clean up inboxes after tests - Use
@AfterEachor try-finally blocks - Use appropriate TTLs - Set shorter TTLs for automated tests, longer for manual testing
- Create fresh inboxes for isolation - Avoid sharing inboxes between unrelated tests
- Handle rate limits - Implement retries for bulk operations
- Close the client - Call
client.close()when done to release resources
// Good: Fresh inbox per test@BeforeEachvoid setUp() { inbox = client.createInbox();}
@AfterEachvoid tearDown() { inbox.delete();}
// Good: Short TTL for automated testsInbox inbox = client.createInbox( CreateInboxOptions.builder() .ttl(Duration.ofMinutes(15)) .build());
// Good: Use try-with-resources for clientClientConfig config = ClientConfig.builder() .apiKey(apiKey) .baseUrl(baseUrl) .build();try (VaultSandboxClient client = VaultSandboxClient.create(config)) { // Use client...}Next Steps
Section titled “Next Steps”- Waiting for Emails - Delivery strategies and filters
- Spam Analysis - Working with spam analysis results
- Import & Export - Persist inbox credentials
- API Reference: Inbox - Complete Inbox API documentation