How to Test Email Sending with Cypress
Cypress specs read best when the email step looks like any other command. This is how to wrap the inbox API into cy.waitForEmail — and how to keep it deterministic under retries and parallel runs.
One task, one command
The polling loop lives in a cy.task (Node side, from the integration guide). Wrap it in a custom command so specs never touch plumbing:
// cypress/support/commands.mjs
Cypress.Commands.add("waitForEmail", (address, subjectRe, timeoutMs = 45000) => {
cy.task("tempxWait", { address, subjectRe, timeoutMs })
.should("not.be.null")
.as("lastEmail");
return cy.get("@lastEmail");
});
And a spec now says what it means:
const addr = "cy-" + Date.now().toString(36) + "-login@tempx.uk";
cy.visit("/login");
cy.get('input[name="email"]').type(addr);
cy.contains("button", "Send code").click();
cy.waitForEmail(addr, "login code").then((msg) => {
const code = (msg.preview.match(/code is (\d{6})/) || [])[1];
cy.get('input[name="code"]').type(code);
cy.contains("button", "Sign in").click();
cy.contains("Welcome back").should("be.visible");
});
Retries: know which loop you are in
Cypress retries commands until their assertions pass — but cy.task is not retried internally; it resolves once. That is why the task itself polls until deadline and resolves null on timeout: the .should("not.be.null") turns a missing email into a readable failure, and test-level retries start clean because each test mints a fresh address.
Parallel runs
- Address uniqueness is the whole game. Timestamp plus test key works; with
cypress-parallelor Dashboard parallelization, add the worker index. - Don't count messages. Assert via
.find()-style matching on subject/sender — never "inbox has exactly 1 message", which parallel runs and resends will break. - Rate limits. 240 reads/minute; the task's 2-second poll has huge headroom, but cap concurrent polling tasks if you shard heavily.
Debugging a failed email step
Open the address in the Tempx app: mail present means the matching or extraction failed (the MIME decoder shows exactly what text the mail carried); no mail means the send side never fired. For header-level surprises, paste the source into the header analyzer.
The starter cy.task config is in the Cypress integration; Playwright and Selenium have equivalents.
Create a temporary email address
Free, instant, no sign-up — messages auto-delete.
Go to your inbox