NukeMail

Temporary Email for Cypress End-to-End Testing

DEVELOPER · 6 min read

TL;DR

How to use disposable email addresses in Cypress tests to automate email verification flows without external mailbox dependencies.

Cypress E2E tests with email verification steps

Email Verification in Cypress Tests

Cypress tests web applications well because it handles automatic waiting, time-travel debugging and deterministic test execution. Your application might require email verification during signup and this is where Cypress hits a real limitation. It lacks a built-in way to check your email. Cypress can fill out the signup form and submit it, but then the test stalls because it needs the verification code or confirmation link from an email that the browser automation layer cannot access.

Some teams work around this by disabling email verification in test environments using feature flags or test-specific configuration. That approach works until the day your verification flow has a bug that only shows up in production because the actual email sending and verification path was never tested end-to-end. Email template rendering issues, broken verification links, incorrect sender addresses and transactional email service misconfigurations all go undetected when you mock the email step.

A temp email API bridges this gap. Cypress's cy.request() command makes HTTP requests to a temp email API to create an address and poll for messages. It keeps everything within the Cypress test runner. You don't need a separate Node.js process or a browser extension or any tooling outside the Cypress toolchain.

This method tests the user journey as it works in production. It covers everything from form submission to email sending, delivery and verification. You get confidence that the entire flow functions correctly rather than just testing the parts that are easy to automate.

Cypress Custom Commands for Email

The cleanest integration pattern uses two Cypress custom commands: cy.createTempEmail() and cy.waitForEmail(). The first command calls the temp email API to create a fresh address. It then stores the inbox ID and the address in Cypress aliases so you can use them in later commands. The second command polls the inbox endpoint repeatedly until a message arrives or the timeout is exceeded.

Custom commands keep your test code readable and maintainable. You don't need inline API calls, retry loops or timeout logic scattered throughout your test files. Each test reads like a natural flow where you create an email, fill a form, submit, wait for an email, extract a code, enter the code and verify success. Each step maps to a single Cypress command with clear intent.

Wrap the polling logic in a recursive cy.request() call and add a cy.wait() delay between attempts. Cypress manages the retry chain through its command queue. You get an automatic test failure with a descriptive error message if the email doesn't arrive within the configured timeout period. This recursive pattern works well with the asynchronous command execution model in Cypress.

Put these custom commands in your cypress/support/commands.js or commands.ts file. They will be available globally across all test specs without explicit imports. This keeps email handling behavior consistent across your entire test suite and makes it easy to update the API integration logic in one location.

Extracting Verification Data

Verification emails come in two main types. You have codes like 6-digit numbers or alphanumeric strings and PINs. Then you have links which are URLs with one-time tokens built into the query parameters or path segments. Your extraction logic needs to handle both formats well because different parts of your application use different verification methods.

To grab numeric codes, use a regex like /\d{6}/ on the plain text body to catch most six-digit verification codes. If you need to handle alphanumeric codes, you should build a specific pattern that matches the format your application uses. To find links, parse the HTML body so you can locate anchor tags with href attributes that match your application domain. You can also use a regex to extract URLs that contain path keywords like "verify" or "confirm" or "activate".

Store extracted data in Cypress aliases using cy.wrap().as() so subsequent commands can reference them cleanly. This keeps the test flow linear and avoids nested callback chains or deeply indented .then() blocks that make Cypress tests hard to follow and debug. You can reference an alias like @verificationCode later by using cy.get('@verificationCode').

Build in defensive checks for edge cases. Consider what happens if the email body contains multiple links or if the verification code appears in both the HTML and plain text bodies in different formats. You should also account for the email not arriving yet when extraction runs. Handling these cases in your custom command prevents subtle test failures that are hard to diagnose.

CI Integration

Cypress tests running in CI environments like GitHub Actions, GitLab CI, CircleCI or Jenkins run headlessly in Docker containers or virtual machines. They need every part of the test to be fully automated. Store your temp email API key as a CI secret and inject it as an environment variable that your Cypress configuration or plugin file reads at runtime. Never hardcode API keys in your test code or cypress.config.js.

If you're running parallel tests with Cypress Cloud (formerly Cypress Dashboard), Sorry Cypress or CI-native parallelization, each test needs its own isolated email address. Don't share addresses between spec files. Cypress parallelization splits specs across multiple machines or containers. Any shared state between specs causes unpredictable failures that are hard to diagnose since the timing depends on which machine runs which spec in what order.

Set your email polling timeout higher in CI than you do for local development. Network latency between CI runners and external services, email service processing time and CI machine performance on shared runners all add delays that don't exist on your local development machine. A 90-second timeout that feels excessive locally prevents flaky failures in CI that waste developer time and erode confidence in the test suite.

Set up Cypress to capture video and screenshots if your email tests fail in CI. If a verification email test breaks at 2 AM during a scheduled pipeline run, those recorded files show exactly what the browser saw while it waited for an email that never showed up. You can then debug the failure without needing to reproduce it by hand.

Why NukeMail Works for Cypress

NukeMail uses regular-looking domains that aren't linked to disposable email in any blocklist. Because of this, the signup forms you test in Cypress accept them without triggering validation rejections. If your application uses a disposable email blocklist (many SaaS products do), NukeMail rotates its domains to ensure your tests stay unblocked even as blocklists are updated.

The 24-hour inbox lifetime is long enough for complex end-to-end flows that span multiple steps and multiple emails. You can perform signup verification followed by a password reset test and email preference changes all using the same inbox. You don't need to rush through a test or worry about the inbox expiring mid-flow. This removes a common source of flaky test failures.

If your team prefers a manual approach during the test development phase, the NukeMail web interface displays incoming emails in real time. You can create an address in NukeMail to use while you manually step through the Cypress test flow. You can visually verify the email content and the behavior of the verification link. Once you have done that, you can translate those manual steps into automated Cypress test code by using the API.

You can use the REST-based API directly with the Cypress cy.request() command because you don't need any extra npm packages, browser extensions or external dependencies. This keeps your Cypress project dependency tree clean. It also reduces the surface area for version conflicts or breaking changes from third-party libraries.

EXAMPLE (javascript)
// cypress/support/commands.js
Cypress.Commands.add('waitForEmail', (inboxId, apiKey) => {
 const poll = (attempt = 0) => {
 return cy.request({
 url: `https://api.example.com/v1/inbox/${inboxId}`,
 headers: { Authorization: `Bearer ${apiKey}` },
 }).then((resp) => {
 if (resp.body.messages?.length > 0) return resp.body.messages[0]
 if (attempt > 20) throw new Error('Email timeout')
 return cy.wait(3000).then(() => poll(attempt + 1))
 })
 }
 return poll()
})
RELATED GUIDES
Temporary Email for App TestingTemporary Email for Developers: Testing, CI/CD and QA...How to Test Email Delivery with Temporary EmailQA Automation with Temporary Email: A Practical GuideUsing a Temporary Email API for Automated TestingDisposable Email for Selenium Test Automation
More Resources
FAQCompare ServicesAll GuidesPremium
Need a temp email?Get a Free Inbox →