MailSlurp logo

Integration testing guide

Test real email and SMS flows in CI, staging, and release gates with MailSlurp.

View Markdown Agent setup

MailSlurp gives QA and release teams real inboxes, real phone numbers, deterministic wait methods, and message quality tooling. The goal is not just "can I receive one email" but "can I prove the whole workflow behaved correctly before we ship."

email testing

What teams use MailSlurp for

  • Signup and verification flows that send email or SMS
  • Password reset and magic-link journeys
  • OTP and MFA checks
  • Notification and transactional email assertions
  • Release gates for delivery, rendering, and message quality

Core release workflow

1. Create isolated inboxes or phone numbers per run

Fresh resources keep tests deterministic and make it easy to trace failures back to one build, one suite, or one campaign.

const inbox = await mailslurp.createInbox();
// { id: '123', emailAddress: '123@mailslurp.com' }

Best practice:

  • Use one inbox per test run or scenario when you can.
  • Use expiring inboxes for short-lived suites.
  • Keep naming and tags aligned with your CI pipeline or release identifier.

2. Wait for real messages instead of sleeping

MailSlurp wait methods let you block until a matching message arrives. This is what removes brittle sleep() calls from browser or API tests.

// wait for the latest unread sms
const [sms] = await mailslurp.waitController.waitForSms({
  waitForSmsConditions: {
    count: 1,
    unreadOnly: true,
    phoneNumberId: phoneNumber.id,
    timeout: 30_000
  }
});
// extract a code from body with regex
expect(sms.body).toContain('Your code: 123');
const [, code] = /.+:\s([0-9]{3})/.exec(sms.body);
expect(code).toEqual('123');

Use wait methods when you need to assert:

  • a message arrived
  • the recipient was correct
  • the subject or sender matched expectations
  • a code or link can be extracted and used in the next test step

3. Open, inspect, and validate message content

After a message lands, teams usually do one of three things:

  • extract links or OTP codes
  • open preview URLs for visual checks
  • validate content quality such as links, images, and supported email features
const {
  // load this in a browser to view teh rendered HTML and interact with it
  plainHtmlBodyUrl,
  // or view full SMTP message
  rawSmtpMessageUrl
} = await mailslurp.emailController.getEmailPreviewURLs({
  emailId: email.id!
});
const { result } = await mailslurp.emailController.checkEmailBodyFeatureSupport({
  emailId: email.id
})
expect(result.detectedFeatures).toContain(EmailFeatureSupportResultDetectedFeaturesEnum.html_doctype)
expect(result.featurePercentages.find(it => it.status === EmailFeatureSupportStatusPercentageStatusEnum.SUPPORTED)?.percentage).toBeGreaterThan(50)

Then deepen the check with:

4. Add release and post-send confidence checks

Single-message waits are useful in tests. Release teams usually add broader controls before launch:

Example projects

Csharp Dotnet Core2 Seleniumcsharp example repository: csharp-dotnet-core2-selenium Csharp Playwright Nunit Sms Otpcsharp example repository: csharp-playwright-nunit-sms-otp Csharp Specflow Mstest Seleniumcsharp example repository: csharp-specflow-mstest-selenium Java Gradle Junit5java example repository: java-gradle-junit5 Java Maven Junit4java example repository: java-maven-junit4 Java Maven Seleniumjava example repository: java-maven-selenium Java Testng Seleniumjava example repository: java-testng-selenium Javascript Cypress Jsjavascript example repository: javascript-cypress-js Javascript Cypress Js Open Emailjavascript example repository: javascript-cypress-js-open-email Javascript Cypress Mailslurp Pluginjavascript example repository: javascript-cypress-mailslurp-plugin Javascript Cypress Newsletter Signupjavascript example repository: javascript-cypress-newsletter-signup Javascript Cypress Sms Testingjavascript example repository: javascript-cypress-sms-testing Javascript Testcafejavascript example repository: javascript-testcafe Javascript Webdriver Iojavascript example repository: javascript-webdriver-io Php Composer Phpunitphp example repository: php-composer-phpunit Php Laravel Phpunitphp example repository: php-laravel-phpunit Playwright Codegen Recorder Nocodeplaywright example repository: playwright-codegen-recorder-nocode Playwright Email Testingplaywright example repository: playwright-email-testing Playwright Lowcode Testingplaywright example repository: playwright-lowcode-testing Playwright Sms Testingplaywright example repository: playwright-sms-testing Python2 Pytestpython2 example repository: python2-pytest Python3 Django Playwrightpython3 example repository: python3-django-playwright Python3 Robotframeworkpython3 example repository: python3-robotframework Ruby Capybara Cucumber Seleniumruby example repository: ruby-capybara-cucumber-selenium Ruby Cucumber Testruby example repository: ruby-cucumber-test Rust Selenium Email Testingrust example repository: rust-selenium-email-testing Totp Mfa Auth0 Seleniumtotp example repository: totp-mfa-auth0-selenium

Test framework guides

Platform and runner guides

Additional example-first frameworks

Practical patterns that reduce flakiness

  • Set explicit wait timeouts that reflect real delivery behavior in your environment.
  • Isolate inboxes or phone numbers so tests do not compete for the same messages.
  • Match on concrete fields such as recipient, subject, or unread status.
  • Keep message extraction helpers in shared test utilities instead of duplicating regex and parsing logic.
  • Use broader delivery checks before major releases instead of relying only on one test inbox.