MailSlurp logo

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.

View MarkdownAgent setup

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.

MailSlurp video Open video on YouTube

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

browser testing

  • 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.

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:

  1. Create a fresh inbox.
  2. Trigger the UI flow (signup/reset/login).
  3. Wait for matching inbound email.
  4. Parse and assert required fields.
  5. Continue flow by visiting extracted link or entering OTP.
  6. 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.

Next step

Create a free account and run one signup + confirmation test end-to-end before expanding to OTP and reset scenarios.