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.
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.
CI stability checklist
- One inbox per test worker.
- Explicit timeouts for asynchronous delivery.
- Minimal assertions first; deep assertions second.
- Retry carefully, not as blanket masking.
- Log failing message payloads for triage.
Related implementation routes
Next step
Create a free account and run one signup + confirmation test end-to-end before expanding to OTP and reset scenarios.
