How to Test Email Signup and Account Verification
Email verification is the gate to most products — get it wrong and new users can’t even start. It’s also one of the easiest flows to break and least tested, because verifying the account means reading an email. Here’s how to test signup + verification end-to-end, whether your app uses a code or a link.
The signup-verification flow
- User registers with an email.
- App creates an unverified account and emails a verification code or link.
- User enters the code (or clicks the link).
- App marks the account verified; the user can proceed.
Set up a disposable inbox
const inbox = await createInbox(`signup-${Date.now()}`)
await page.goto('https://staging.myapp.com/signup')
await page.getByLabel('Email').fill(inbox.address)
await page.getByLabel('Password').fill('correct-horse-battery-staple')
await page.getByRole('button', { name: 'Sign up' }).click()(The createInbox/waitForEmail helpers come from the CI/CD guide.)
If you verify with a code
const email = await waitForEmail(inbox._id, 'has_code=true')
await page.getByLabel('Verification code').fill(email.extractedCodes[0])
await page.getByRole('button', { name: 'Verify' }).click()
await expect(page.getByText('Welcome')).toBeVisible()If you verify with a link
const email = await waitForEmail(inbox._id, 'subject=' + encodeURIComponent('Confirm your email'))
await page.goto(email.primaryLink)
await expect(page.getByText('Email confirmed')).toBeVisible()Don’t forget the negative cases
Verification is where real bugs live — assert the negatives too:
- Unverified users are blocked from the actions verification is meant to gate.
- A wrong or expired code is rejected with a clear message.
- The code/link is single-use.
- Resending verification produces a fresh, working code (and ideally invalidates the old one).
Bonus: assert the email itself
Since you have the raw message, assert on it too — that the email is correct, not just that the flow works:
expect(email.from).toContain('noreply@myapp.com')
expect(email.subject).toMatch(/verify|confirm/i)
expect(email.verdicts.dkim).toBe('PASS') // it's authenticatedThat last line checks the email passes DKIM — a quick guard against deliverability regressions. See testing SPF, DKIM, and DMARC for more.
Related reading
Try it in two minutes
Create a disposable prefix@devmailr.app inbox over the API, send mail to it from your app, and read it in your tests. Free plan, no card required.