← All posts
2026-04-14

Testing email verification without mocking the inbox

Signup flows almost always have a step that leaves the browser: a verification email lands somewhere else, and the user has to go get it. Most test suites solve this by not testing it — they stub the email service, hardcode a token, and jump straight to the "verified" state.

That's a real gap. The stub can pass while the actual email is broken: wrong sending domain, a template with a dead link, a rate limiter that silently drops the second send in a session. None of that shows up until a real user hits it.

Polling a real mailbox

Test Chain uses Mailsac under the hood, which gives us disposable inboxes with no account setup — any *@mailsac.com address just works. The {{testEmail}} template variable generates a fresh one per replay run, so concurrent runs never collide on the same inbox.

An emailAction step then polls that inbox:

POST /api/email/poll
{ "email": "automation-ts-r1u4dobl@mailsac.com", "timeout": 30000 }

We poll every 2.5 seconds, up to a 60-second ceiling, and support three things you can do once the mail arrives: pull a one-time code out of the body with a regex, extract a specific link by index, or just click the first link the message contains. Links are matched against the plain-text part of the email and trailing punctuation is stripped — "click here." should not become part of the URL.

What this catches that mocks don't

None of these are exotic failures. They're the kind of thing that breaks quietly in production while every stubbed test suite stays green.