How to Test OTP Emails Automatically

One-time passwords close the loop on login, 2FA and sensitive actions — which makes them the most valuable email your app sends, and the one teams most often test by hand. Here is the automated version.

The loop you are automating

Every email OTP flow is the same five beats: submit the identifier (email or username), the app sends a code, your test reads the mailbox, extracts the digits, feeds them back and asserts success. None of those steps needs a human — the only missing piece used to be a mailbox the test could read. A disposable Tempx inbox is exactly that: pick any name, mail arrives through our MX, and GET /api/inbox?address=… returns it as JSON with no authentication.

Where the code lives

The inbox API returns, per message: subject, from, and preview — the first 140 characters of the text part. OTP templates almost always open with the code, so the preview is the sweet spot. Two rules make extraction robust:

// otp-test.mjs — request, poll, extract, verify
const ADDR = "otp-" + Date.now().toString(36) + "@tempx.uk";

await api.post("/login/otp", { email: ADDR });          // 1+2. request the code

let code = null;                                        // 3. poll the inbox
for (let i = 0; i < 30 && !code; i++) {
  const res = await fetch("https://tempx.uk/api/inbox?address=" + ADDR);
  const { messages } = await res.json();
  const msg = messages.find((m) => /your login code/i.test(m.subject));
  if (msg) code = (msg.preview.match(/code is (\d{6})/) || [])[1];
  if (!code) await new Promise((r) => setTimeout(r, 2000));
}

if (!code) throw new Error("no OTP arrived");           // 4. extract (above)

const done = await api.post("/login/otp/verify",        // 5. feed it back
  { email: ADDR, code });
if (!done.ok) throw new Error("OTP rejected");

The three flakiness traps

Let an agent do the clicking

If your E2E layer is an AI agent rather than a script, Tempx's MCP server has a tool built for this: wait_for_email blocks server-side until a matching message lands (5–175 s), so the agent's loop is submit → wait → read → continue with no polling code at all. See the MCP integration.

Framework-specific versions of the loop: Playwright and Cypress.

Create a temporary email address

Free, instant, no sign-up — messages auto-delete.

Go to your inbox