Skip to content
Poofbox

Guide · Playwright

Test sign-up emails in Playwright, without a shared inbox.

Verification codes, magic links and password resets are the flows most likely to break and the hardest to test. Give every test its own disposable address, wait for the email, and read the code or link from it.

Three steps

  1. 1

    Install the package

    One small dependency, no IMAP client or mail server to run.

    npm install --save-dev poofbox

  2. 2

    Add your token

    Dashboard → MCP access → New token. Save it as POOFBOX_TOKEN locally and in CI.

    POOFBOX_TOKEN=pbm_…

  3. 3

    Wait for the email

    waitForEmail() returns the moment it lands, with the code and link picked out.

    await inbox.waitForEmail()

signup.spec.ts

import { test, expect } from '@playwright/test';
import { Poofbox } from 'poofbox';

const pb = new Poofbox(); // reads POOFBOX_TOKEN

test('sign up and verify the email address', async ({ page }) => {
  const inbox = await pb.createInbox();

  await page.goto('/signup');
  await page.getByLabel('Email').fill(inbox.address);
  await page.getByLabel('Password').fill('correct horse battery staple');
  await page.getByRole('button', { name: 'Create account' }).click();

  const email = await inbox.waitForEmail({ subject: 'verify' });
  await page.getByLabel('Verification code').fill(email.code!);
  await page.getByRole('button', { name: 'Verify' }).click();

  await expect(page.getByText('Welcome')).toBeVisible();
  await inbox.delete();
});

Magic links and fixtures

The same two calls cover login links and password resets. A fixture gives every test its own inbox and cleans up after it.

Magic link login

magic-link.spec.ts

test('log in with a magic link', async ({ page }) => {
  const inbox = await pb.createInbox();
  await page.goto('/login');
  await page.getByLabel('Email').fill(inbox.address);
  await page.getByRole('button', { name: 'Email me a link' }).click();

  const { link } = await inbox.waitForEmail({ subject: 'sign in' });
  await page.goto(link!);
  await expect(page.getByText('Signed in')).toBeVisible();
  await inbox.delete();
});

A fresh inbox for every test

fixtures.ts

import { test as base } from '@playwright/test';
import { Poofbox, type Inbox } from 'poofbox';

const pb = new Poofbox();

export const test = base.extend<{ inbox: Inbox }>({
  inbox: async ({}, use) => {
    const inbox = await pb.createInbox();
    await use(inbox);
    await inbox.delete();
  },
});

What waitForEmail() returns

No HTML parsing in your tests: the code and the link come back as fields, already ranked.

code

The most likely one-time code, e.g. "482913".

link

The best action link: verify, confirm, magic link or reset.

codes · links

Every candidate, ranked, if you need another one.

subject · from · text

For assertions on the email itself.

attachments

Names, types and signed download URLs.

receivedAt · id

When it arrived, and an id for readEmail().

Run it in CI

Add the token as a repository secret and pass it to the test step. Use an MCP token, never your license key: tokens can be revoked one by one.

.github/workflows/e2e.yml

- name: Playwright tests
  run: npx playwright test
  env:
    POOFBOX_TOKEN: ${{ secrets.POOFBOX_TOKEN }}

Tips

Filter, don’t sleep

Pass subject or from, so a welcome email is never mistaken for the verification one.

No race to lose

Mail that lands after the inbox was created counts, even if it arrives before you start waiting.

One inbox per test

Keeps parallel workers apart. Personal: 10 active inboxes and 5 parallel waits; Pro: 50 and 20.

Clean up

Delete inboxes when done to free the slot. A deleted address is never given to anyone else.

Long-lived test users

Accounts you keep, like a test user that gets password resets, belong on the permanent poofy.uk domain.

Agents driving the browser

With Claude Code, Cursor or the Playwright MCP server, connect Poofbox over MCP and let the agent call the tools itself.

Personal €9.99 or Pro €34.99 a year

Plus VAT. Comparing tools? See Poofbox vs Mailosaur and vs MailSlurp.

Get Poofbox