The Problem
- Email tests are flaky because polling-based solutions miss timing windows
- Setting up test email infrastructure is complex and time-consuming
- Shared test inboxes cause race conditions between parallel tests
- Extracting verification codes and links from emails requires fragile regex
- Email testing slows down CI/CD pipelines with unnecessary waits
Why Existing Solutions Fall Short
Polling-based email checks introduce delays and flakiness
Shared test accounts cause conflicts in parallel test runs
Mock email services don't test the real email delivery path
Manual email verification makes automated testing impossible
You shouldn't have to build this yourself.
How Mailhooks Solves This
Instant Email Access
Query received emails via API — no polling or webhooks needed in tests.
Unique Test Addresses
Generate unique email addresses per test to avoid conflicts.
Structured Content
Access parsed email body, subject, and attachments for assertions.
CI/CD Ready
Fast, reliable email testing that works in any CI environment.
How It Works
Generate test email
Create a unique address for this test run.
Trigger email
Your app sends an email (signup, reset, etc.).
Query inbox
Use the Mailhooks API to fetch received emails.
Assert
Verify subject, content, links, and attachments.
Continue test
Extract verification codes and proceed.
Code Example
Use the Mailhooks API in your Playwright or Cypress tests.
Webhook Payload
// API Response: GET /api/v1/emails
{
"emails": [
{
"id": "msg_test456",
"from": "[email protected]",
"to": "[email protected]",
"subject": "Verify your email",
"text": "Your code is: 847291",
"html": "Your code is: 847291
",
"receivedAt": "2025-01-15T10:30:00Z"
}
]
}Handler Code
// Playwright test example
import { test, expect } from '@playwright/test';
test('user receives verification email', async ({ page }) => {
// Generate unique test email
const testEmail = `test-${Date.now()}@inbox.mailhooks.dev`;
// Sign up with test email
await page.goto('/signup');
await page.fill('[name="email"]', testEmail);
await page.click('button[type="submit"]');
// Wait for and fetch the verification email
const response = await fetch(
`https://api.mailhooks.dev/v1/emails?to=${testEmail}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const { emails } = await response.json();
// Assert on email content
expect(emails[0].subject).toBe('Verify your email');
// Extract verification code
const code = emails[0].text.match(/\d{6}/)?.[0];
expect(code).toBeTruthy();
// Continue test with code
await page.fill('[name="code"]', code);
});Frequently Asked Questions
Every inbox can be configured with sender filtering rules. You can whitelist specific domains or email addresses, or use our webhook to implement your own spam filtering logic. Emails that don't match your rules are automatically rejected.
Webhooks are typically delivered within 100-500ms of email receipt. We process emails in real-time with no polling delays. For high-availability applications, we also offer webhook retries with exponential backoff.
Mailhooks is built specifically for inbound email. We offer simpler setup (no DNS changes required for testing), better attachment handling with direct download URLs, and a developer-first API for fetching emails programmatically—perfect for E2E testing.
Yes! You can connect your own domain with simple DNS configuration. We also provide free subdomains on inbox.mailhooks.dev for testing and development.
We automatically retry failed webhooks with exponential backoff for up to 24 hours. You can also use our API to fetch any missed emails. All emails are stored and accessible via the dashboard.
Get Started in 3 Steps
Takes ~2 minutes — no email infrastructure required.
Create a Mailhooks account
Sign up for free in seconds.
Create an inbox
Get a unique email address for your use case.
Add your webhook URL
Point to your endpoint and start receiving emails.