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.

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.

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.

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.

Next step

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