TMailr

← All writing

For developers

Testing signup emails in CI without a real mailbox

31 July 2026 · 5 min read

The usual test does this: trigger a signup, sleep ten seconds, poll a mailbox, hope. It fails on a slow day and wastes ten seconds on every fast one.

Use a catch-all, not an inbox per test

A sandbox with plus-addressing means every actor in a test has their own address without creating anything first. `yours+alice@`, `yours+bob@`, `yours+run-8412@` all land in one place, and each message records which address received it.

const sb = await tm.createSandbox("checkout-tests");
await signUp({ email: sb.catchAll.replace("anything", "alice") });
const msg = await tm.waitForMessage(sb.id, { to: "alice" });
expect(msg.otp).toBeTruthy();

Wait for a condition, not a duration

A helper that polls until a matching message arrives is faster than any fixed sleep and more reliable than a short one. When it gives up it should say what it was looking for and how many other messages did arrive, because "timed out" alone will not tell you the mail went to the wrong address.

Let the code be extracted for you

One-time codes and sign-in links are the thing you actually want. Have the service pull them out, so your test is not maintaining a regular expression against somebody else’s template.

More on for developers