The pain of testing transactional email workflows in CI/CD
Automating end-to-end browser tests for user onboarding, magic link sign-in, and two-factor SMS/email OTP verification has historically been one of the most brittle parts of software delivery.
Engineering teams commonly resort to anti-patterns:
- Shared Corporate Test Inboxes: Multiple CI runners concurrently testing signups collide in the same mailbox, causing race conditions and flaky test runs.
- IMAP / POP3 Polling Loops: Test scripts poll an external mail server every 3 seconds, adding 15 to 45 seconds of idle wait time to every single test execution.
- Synthetic Database Bypasses: Mocking the email service and querying the database directly fails to verify that MIME templates, links, and headers render correctly.
Architecture of on-demand ephemeral inboxes
An ephemeral test inbox is a lightweight, disposable mail container minted on-demand for a single test runner. It requires zero DNS configuration, zero mailbox setup, and automatically expires when the test completes.
When your test suite initializes a test scenario, it requests an ephemeral address scoped to your dedicated test domain (e.g., test-89f2a@inbound.sadasend.com). Any message dispatched to that address is ingested by the inbound MX router, sanitized, and streamed directly to your test runner via an open event connection.
Real-world Playwright test with sub-150ms OTP extraction
Using the official TypeScript client, your test script can listen for incoming verification codes with zero polling loops. The waitForCode promise resolves the instant the inbound email reaches our MX servers:
import { test, expect } from '@playwright/test';
import { SadaSend } from 'sadasend';
const sadasend = new SadaSend({ apiKey: process.env.SADASEND_API_KEY });
test('User signs up and completes 2FA verification', async ({ page }) => {
// 1. Mint an isolated ephemeral test inbox
const inbox = await sadasend.inbound.createEphemeralInbox();
// 2. Navigate to signup and submit the ephemeral address
await page.goto('https://app.example.com/signup');
await page.fill('input[name="email"]', inbox.email);
await page.click('button[type="submit"]');
// 3. Await 6-digit OTP code directly from inbound event stream (sub-150ms)
const otpCode = await inbox.waitForCode({ pattern: /\b\d{6}\b/, timeoutMs: 10000 });
// 4. Fill the 2FA input and assert dashboard access
await page.fill('input[name="otp"]', otpCode);
await page.click('button:has-text("Verify")');
await expect(page).toHaveURL('https://app.example.com/dashboard');
// 5. Explicitly destroy the inbox (or let it auto-decay in 15 minutes)
await inbox.destroy();
});Zero data retention and hermetic test teardown
In automated testing environments, compliance and clean state management are critical. Retaining thousands of test email bodies in production databases creates security hazards and burns storage.
Ephemeral test inboxes enforce hermetic teardown:
- Automated 15-Minute Expiry: Any inbox created without an explicit destroy call is automatically purged from memory and database storage after 15 minutes.
- Zero PII Persistence: Incoming email bodies are streamed in-memory to the connected test socket and discarded unless explicit retention flags are passed.
- Zero Cost Overhead: Ephemeral test inboxes do not count toward paid contact tiers or domain limits.
Send transactional emails in under 3 minutes
Low-latency edge dispatch, custom SMTP relay, 100% SPF/DKIM alignment, and automated suppression firewalls. 6,000 free sends every month without a credit card.