NEW
Back to Blog
Tutorials

Testing Email Flows with Playwright and Temporary Inboxes

Code editor showing Playwright test automation

Testing email flows in your application can be challenging. You need real email addresses that receive real emails, but you don't want to clutter personal inboxes or deal with flaky third-party email services.

This tutorial shows you how to use destroy.network's API with Playwright to create robust, automated email tests.

Why Automate Email Testing?

Email is critical to most applications-user registration, password resets, notifications, and transactional emails all rely on it. Yet email testing is often skipped or done manually because it's perceived as difficult.

With proper automation, you can:

  • Catch email delivery issues before they reach production
  • Verify email content and formatting automatically
  • Test email-dependent user flows end-to-end
  • Run tests in CI/CD without manual intervention

Setting Up the Test Environment

First, let's set up a Playwright test file with the necessary dependencies:

test/helpers/email.tstypescript
1import { test, expect } from '@playwright/test';2 3const API_URL = 'https://destroy.network/api';4 5interface Inbox {6  id: string;7  address: string;8}9 10interface Message {11  id: string;12  subject: string;13  from: string;14  body: string;15}16 17async function createInbox(): Promise<Inbox> {18  const res = await fetch(`${API_URL}/inbox`, {19    method: 'POST',20    headers: { 'Content-Type': 'application/json' },21    body: JSON.stringify({ domain: 'destroy.email' }),22  });23  return res.json();24}25 26async function waitForEmail(27  inboxId: string,28  timeout = 3000029): Promise<Message> {30  const start = Date.now();31  while (Date.now() - start < timeout) {32    const res = await fetch(`${API_URL}/inbox/${inboxId}/messages`);33    const messages = await res.json();34    if (messages.length > 0) {35      return messages[0];36    }37    await new Promise(r => setTimeout(r, 1000));38  }39  throw new Error('Timeout waiting for email');40}

Testing User Registration

Here's a complete example testing a signup flow with email verification:

test/registration.spec.tstypescript
1test('user registration with email verification', async ({ page }) => {2  // Create a temporary inbox for this test3  const inbox = await createInbox();4 5  // Navigate to signup page6  await page.goto('/signup');7 8  // Fill out registration form9  await page.fill('[name="email"]', inbox.address);10  await page.fill('[name="password"]', 'SecureP@ssw0rd!');11  await page.click('button[type="submit"]');12 13  // Wait for confirmation message14  await expect(page.locator('.success-message')).toBeVisible();15 16  // Wait for verification email17  const email = await waitForEmail(inbox.id);18 19  // Verify email subject20  expect(email.subject).toContain('Verify your email');21 22  // Extract verification link from email body23  const linkMatch = email.body.match(/href="([^"]+verify[^"]+)"/);24  expect(linkMatch).toBeTruthy();25 26  // Visit verification link27  await page.goto(linkMatch![1]);28 29  // Verify account is now active30  await expect(page.locator('.verified-message')).toBeVisible();31});

Testing Password Reset

Password reset flows are another common use case:

test/password-reset.spec.tstypescript
1test('password reset flow', async ({ page }) => {2  const inbox = await createInbox();3 4  // Create user with this email first (setup)5  // ... your user creation logic6 7  await page.goto('/forgot-password');8  await page.fill('[name="email"]', inbox.address);9  await page.click('button[type="submit"]');10 11  // Wait for reset email12  const email = await waitForEmail(inbox.id);13 14  expect(email.subject).toContain('Reset your password');15 16  // Extract reset link and complete flow17  const resetLink = email.body.match(/href="([^"]+reset[^"]+)"/);18  await page.goto(resetLink![1]);19 20  await page.fill('[name="newPassword"]', 'NewSecureP@ss!');21  await page.fill('[name="confirmPassword"]', 'NewSecureP@ss!');22  await page.click('button[type="submit"]');23 24  await expect(page.locator('.password-updated')).toBeVisible();25});

CI/CD Integration

These tests run perfectly in CI/CD environments. No email server setup, no SMTP configuration-just HTTP requests to the destroy.network API.

For high-volume testing, consider using an API key to increase rate limits and access additional features.

Best Practices

  • Create a new inbox for each test to ensure isolation
  • Use meaningful timeout values based on your email delivery speed
  • Clean up inboxes after tests or let them expire naturally
  • Parse emails carefully-HTML content may vary
  • Consider using the API's webhook feature for real-time notifications

Next Steps

Ready to start automating your email tests? Check out our API documentation for the complete reference, and create your first test inbox to see it in action.