guides
Cypress Email Testing Tutorial with MailSlurp
Step-by-step Cypress email testing tutorial with MailSlurp: create inboxes, assert signup links and OTP codes, and stabilize CI runs.
MailSlurp integrates with Cypress so you can test real email behavior in browser-driven end-to-end flows. This tutorial covers setup, test structure, and CI hardening. For the concise production pattern with deterministic matching and cleanup, start with the canonical Cypress email testing guide.
What you can validate
Use Cypress + MailSlurp for flows that break often in production:
- Signup confirmation links
- Password reset links
- OTP passcodes
- Invitation acceptance
- Transactional email content assertions
How the stack fits together

- Cypress drives browser actions.
- MailSlurp creates and manages real test inboxes.
- Your tests wait for and assert incoming messages.
This avoids brittle mocks and gives stronger confidence in release pipelines.
Setup links
Configure Cypress and MailSlurp
Start with client configuration:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
defaultCommandTimeout: 30000,
requestTimeout: 30000,
viewportHeight: 800,
viewportWidth: 800,
videoCompression: false,
e2e: {
setupNodeEvents(on, config) {},
},
})
Then implement login or signup helpers in your tests:
it('can log in with confirmed account', () => {
cy.contains('Sign in to your account');
// fill out username (email) and password
cy.get('[data-test="username-input"]').type(emailAddress);
cy.get('[data-test="sign-in-password-input"]').type(password);
// submit
cy.get('[data-test="sign-in-sign-in-button"]').click();
});
Add inbox helpers
Create reusable commands for inbox provisioning and retrieval:
const { MailSlurp } = require('mailslurp-client');
// set your api key with an environment variable `CYPRESS_API_KEY` or configure using `env` property in config file
// (cypress prefixes environment variables with CYPRESS)
const apiKey = Cypress.env('API_KEY')
const mailslurp = new MailSlurp({ apiKey });
Cypress.Commands.add("createInbox", () => {
return mailslurp.createInbox();
});
Cypress.Commands.add("waitForLatestEmail", (inboxId) => {
// how long we should hold connection waiting for an email to arrive
const timeoutMillis = 30_000;
return mailslurp.waitForLatestEmail(inboxId, timeoutMillis)
});
Use generated inboxes in each test for isolation:
const password = "test-password";
let inboxId;
let emailAddress;
it('can generate a new email address and sign up', () => {
// see commands.js custom commands
cy.createInbox().then(inbox => {
// verify a new inbox was created
assert.isDefined(inbox)
// save the inboxId for later checking the emails
inboxId = inbox.id
emailAddress = inbox.emailAddress;
// sign up with inbox email address and the password
cy.get('input[name=email]').type(emailAddress);
cy.get('input[name=password]').type(password);
cy.get('[data-test="sign-up-create-account-button"]').click();
});
});
Practical test blueprint
A robust Cypress email test usually follows this shape:
- Create a fresh inbox.
- Trigger the UI flow (signup/reset/login).
- Wait for matching inbound email.
- Parse and assert required fields.
- Continue flow by visiting extracted link or entering OTP.
- Delete the inbox after the assertion, including failed runs.
CI stability checklist
- One inbox per test worker.
- Subject, sender, or run-token matching instead of a loose latest-email lookup.
- Explicit bounded timeouts for asynchronous delivery.
- Minimal assertions first; deep assertions second.
- Retry carefully, not as blanket masking.
- Keep inbox and message IDs with failing test evidence for triage.
- Delete short-lived inboxes from
afterEach.
Related implementation routes
- Email integration testing
- Email Sandbox
- Email testing API
- Webhook reliability testing
- Cypress project example
Next step
Create a free account and run one signup + confirmation test end-to-end before expanding to OTP and reset scenarios.
