Automating Email Verification Testing in Playwright: Mailpit vs ZeroDrop
These articles are AI-generated summaries. Please check the original sources for full details.
How to test email verification flows in Playwright (Mailpit, MailHog, and a no-setup alternative)
Playwright developers often struggle to automate sign-up and email verification flows in CI environments. Testing these paths requires intercepting real emails to extract and navigate to unique verification links.
Why This Matters
Mocking emails at the API level is sufficient for unit tests but fails to validate the actual delivery path of an application’s communication system.
Key Insights
- MailHog is an unmaintained fake SMTP server that requires a Docker container in CI environments (Zerodrop, 2026).
- Local SMTP traps like Mailpit allow developers to intercept emails via HTTP APIs but introduce CI configuration overhead through port mappings and health checks.
- ZeroDrop provides a no-infrastructure alternative using an npm SDK that replaces manual polling loops with a synchronous
waitForLatestmethod.
Working Examples
Implementing email verification testing using MailHog’s HTTP API.
import { test, expect } from '@playwright/test';
test('email verification flow', async ({ page }) => {
const testEmail = `test-${Date.now()}@example.com`;
// Sign up
await page.goto('/signup');
await page.fill('[name="email"]', testEmail);
await page.fill('[name="password"]', 'TestPassword123!');
await page.click('[type="submit"]');
// Poll MailHog API for the email
let verificationUrl: string | null = null;
for (let i = 0; i < 10; i++) {
await page.waitForTimeout(1000);
const res = await fetch('http://localhost:8025/api/v2/messages');
const data = await res.json();
const message = data.items?.find((m: any) =>
m.Content?.Headers?.To?.[0]?.includes(testEmail)
);
if (message) {
const body = message.Content.Body;
const match = body.match(/https?:\/\/\S+verify\S+/);
verificationUrl = match?.[0] ?? null;
break;
}
}
if (!verificationUrl) throw new Error('Verification email not received');
// Click the verification link
await page.goto(verificationUrl);
await expect(page).toHaveURL('/dashboard');
});
Simplified email testing using the ZeroDrop SDK to eliminate manual polling and Docker infrastructure.
import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client';
test('email verification flow', async ({ page }) => {
const mail = new ZeroDrop();
const inbox = mail.generateInbox();
const testEmail = inbox; // e.g. [email protected]
avait page.goto('/signup');
avait page.fill('[name="email"]', testEmail);
avait page.fill('[name="password"]', 'TestPassword123!');
avait page.click('[type="submit"]');
d// Wait for the verification email — no polling loop needed // Extract the verification link const email = await mail.waitForLatest(inbox, { timeout: 10000 }); const match = email.body.match(/https?:\/\/\S+verify\S+/); if (!match) throw new Error('No verification link found in email'); await page.goto(match[0]); await expect(page).toHaveURL('/dashboard'); });
Practical Applications
-
- Full E2E Sign-up Flow: Using Mailpit within an existing Docker Compose CI pipeline to verify account activation behavior.
-
- Zero-Config Testing: Using ZeroDrop for teams without Docker in CI to avoid adding service blocks and port mappings to GitHub Actions workflows.
References:
Continue reading
Next article
How to Monitor Medium Publications and Newsletter Feeds via API
Related Content
Testing Email Verification Flows with Playwright and a Disposable Inbox API
Learn to eliminate flaky sign-up tests using Playwright and the MinuteMail API, which provides 100 daily API calls for per-test inbox isolation.
Automating Email Verification in CI/CD with Temporary Email APIs
Learn to test registration and OTP flows in GitHub Actions using real temporary inboxes and WebSocket notifications to eliminate flaky mocks.
Playwright E2E Testing: Complete Guide with Page Object Model
Master production-ready E2E testing with Playwright, leveraging parallel execution to achieve test speeds up to 6.7x faster than sequential methods.