IQMailPilot

Ship email flows with the same confidence as your API.

Capture staging and CI mail, inspect every message, and assert with a typed waitFor() — so OTPs, receipts, and resets never slip past QA.

Live capture
*@serverKey.mail.iqmailpilot.com

noreply@your-app.com

OTPjust now

Verify your email address

billing@your-app.com

HTML2m ago

Your payment receipt

security@your-app.com

Link6m ago

Password reset requested

Message preview

Your verification code is ready. It expires in 10 minutes.

waitFor() resolved

1.2s

Captured

1,284

Servers

6

Ingest p95

48ms

Sub-second

SMTP capture to API

Unlimited

Catch-all addresses

Realtime

WebSocket delivery

Isolated

Per-workspace data

Drops into the stack you already run

PlaywrightCypressVitestJestGitHub ActionsGitLab CINode.jsNestJSNext.jsPythonGoNodemailerPlaywrightCypressVitestJestGitHub ActionsGitLab CINode.jsNestJSNext.jsPythonGoNodemailer

The problem

Email is usually the least tested part of the product

Sign-up, password reset, and billing all depend on a message arriving with the right content. Most teams verify that by hand — and find out it broke from a customer.

Tests that sleep instead of assert

Arbitrary waits make suites slow and flaky. IQMailPilot long-polls the API until the message exists, so a passing test means the email genuinely arrived.

One shared mailbox, many engineers

Parallel runs collide when everyone reads the same inbox. Every environment, branch, and CI job gets its own catch-all domain instead.

No safe way to verify real mail

Sending staging email to real addresses risks reaching customers. Traffic is contained inside your workspace while still using ordinary SMTP.

Platform

Everything needed to test email properly

Capture, inspection, automation, and access control in a single workspace — built on standard SMTP so nothing about your application has to change.

Catch-all inboxes

Every address on your server domain is captured automatically. One wildcard DNS record covers every server you will ever create.

Complete message inspection

Read the rendered HTML, plain-text alternative, every RFC 822 header, and each attachment — or download the original .eml.

Deterministic assertions

A typed waitFor() blocks until a matching message lands, then hands your test the parsed body to extract codes and links.

Realtime dashboard

Messages appear the moment they are accepted over SMTP. No polling loops or manual refreshes while you debug a flow.

Scoped API keys

Issue separate credentials per pipeline, rotate them independently, and revoke access without touching user passwords.

Role-based workspaces

Invite engineers, QA, and contractors with defined roles so access follows your team structure, not a shared login.

How it works

Integrated in an afternoon

Three configuration changes stand between your current setup and email coverage in CI.

  1. 01

    Create an email server

    Each server gets a dedicated catch-all domain and its own SMTP credentials, generated instantly in the dashboard.

  2. 02

    Point your app at it

    Swap the SMTP host in your staging and CI configuration. Your application code and templates stay exactly the same.

  3. 03

    Assert in your test suite

    Call waitFor() with the recipient and subject. Extract the verification code, follow the link, and finish the journey.

For developers

An API your test suite can rely on

Install @mailpilot/sdk for typed access, or call the REST endpoints directly from any language in your pipeline.

  • Blocking waitFor() with an explicit timeout
  • Filter by recipient, subject, or full-text search
  • Parsed HTML, text, headers, and attachments
  • Purge a server for a clean slate between runs
wait-for-message.ts
import { MailpilotClient } from '@mailpilot/sdk';

const mail = new MailpilotClient({
  apiKey: process.env.MAILPILOT_API_KEY!,
  baseUrl: process.env.MAILPILOT_API_URL!,
});

const serverId = process.env.MAILPILOT_SERVER_ID!;
const sentTo = process.env.MAIL_TO!;
const receivedAfter = new Date().toISOString();

// Trigger the email in your application, then wait:
const message = await mail.messages.waitFor(serverId, {
  sentTo,
  receivedAfter,
  timeout: 30,
});

const code = message.textBody?.match(/\d{6}/)?.[0];

Comparison

Why a dedicated test inbox wins

CapabilityShared mailboxProduction providerIQMailPilot
Isolated inbox per test run
Programmatic message retrieval
Blocking wait for delivery
Zero risk of mailing real users
Full headers and raw source
Accepts real inbound internet mail

Pricing

Straightforward plans

Start on the free plan and move up when your team and message volume grow.

Free

$0forever

For a single developer validating a flow.

  • 1 email server
  • 3 team members
  • 500 messages / month
  • Full API and SDK access
Most popular

Pro

$29/ month

For product teams running email in CI.

  • 10 email servers
  • 25 team members
  • 10,000 messages / month
  • Extended retention windows
  • Priority support

Enterprise

Custom

For organisations with many environments.

  • 100 email servers
  • 500 team members
  • 1M messages / month
  • SSO-ready workspaces
  • Deployment guidance

FAQ

Questions teams ask first

A shared mailbox gives you one address and no API. IQMailPilot gives every environment, branch, or test run its own catch-all domain, so parallel test runs never collide. Your tests query messages by recipient and subject instead of a human opening an inbox.

No. You configure DNS once for your mail domain using a wildcard record. After that, every server you create in the dashboard gets a working catch-all subdomain immediately — no per-server DNS entries and no propagation wait.

Yes. IQMailPilot accepts inbound internet mail over standard MX on port 25, so you can forward or send from Gmail, Outlook, or any provider to verify how third-party mail renders. Application traffic uses authenticated submission on port 587.

Create scoped API keys per pipeline with an explicit prefix so you can tell live and test credentials apart at a glance. Keys can be rotated or revoked independently, and no key ever exposes a user password or SMTP credential.

Each server has a retention window, and a background worker removes messages and stored attachments once they age out. You can also purge a server manually between test runs to guarantee a clean slate.

If it can make an HTTP request, yes. The TypeScript SDK is the fastest path for Playwright, Cypress, Vitest, and Jest, and the REST API covers everything else — Python, Go, Java, or a shell script in your pipeline.

Put your email flows under test today

Create a workspace, point one environment at IQMailPilot, and watch the first message arrive in the dashboard within minutes.