Email Testing for Developers
Test emails like you debug code. SMTP in, IMAP/API out. Inspect headers, MIME and raw source. Nothing leaves the sandbox.
SMTP, IMAP, POP3
Your existing mail clients work out of the box. No vendor SDK, no lock-in.

After delivery
Check what arrived in the UI or wire it into CI.
- Delivery checksHTML preview, text, headers, raw source. Plus SPF/DKIM/DMARC results via API.
- CI-readyStandard SMTP - any CI that sends email works. GitHub Actions, Jenkins, GitLab CI, whatever you use.
- Deliverability auditSender config, HTML structure, links, and the content patterns spam filters flag. Grouped by severity.

Quickstart
Send, read, assert
Your app sends over SMTP. Your test reads the result over the API. The whole loop fits on one screen.
# create an inbox
curl -X POST https://api.smtp.dev/accounts \
-H "X-API-KEY: $SMTP_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"address": "qa@example.com", "password": "use-a-secret"}'
# your app sends to it, then read what arrived
curl "https://api.smtp.dev/accounts/$ACCOUNT/mailboxes/$INBOX/messages" \
-H "X-API-KEY: $SMTP_DEV_API_KEY"
const transport = nodemailer.createTransport({
host: 'send.smtp.dev',
port: 587,
requireTLS: true,
auth: { user: 'ci@example.com', pass: process.env.SMTP_DEV_PASSWORD },
})
await transport.sendMail({
from: 'ci@example.com',
to: 'qa@example.com',
subject: `Welcome ${Date.now()}`,
text: 'Confirm your address: https://example.com/confirm/abc123',
})
// read it back over the API, newest first
const { member } = await fetch(
`https://api.smtp.dev/accounts/${account}/mailboxes/${inbox}/messages`,
{
headers: { 'X-API-KEY': process.env.SMTP_DEV_API_KEY },
},
).then(res => res.json())
assert.match(member[0].text, /\/confirm\//)
msg = EmailMessage()
msg["From"], msg["To"] = "ci@example.com", "qa@example.com"
msg["Subject"] = "Reset your password"
msg.set_content("https://example.com/reset/abc123")
with smtplib.SMTP("send.smtp.dev", 587) as smtp:
smtp.starttls()
smtp.login("ci@example.com", os.environ["SMTP_DEV_PASSWORD"])
smtp.send_message(msg)
# read it back over the API, newest first
messages = requests.get(
f"https://api.smtp.dev/accounts/{account}/mailboxes/{inbox}/messages",
headers={"X-API-KEY": os.environ["SMTP_DEV_API_KEY"]},
).json()["member"]
Features
Custom Domains
Bring your own domains and subdomains. One MX record each.
Disposable Accounts
Create an address per test run over the API. Delete it after.
Unlimited Messages
On every plan - no daily caps, no metering.
Sandboxed
Receives real email from any service. Sends only within the sandbox.
SPF, DKIM, DMARC
Checked on every inbound message. Results in the UI and the API.
Retention Timers
Messages kept for your plan's window, up to 90 days. Per-message expiry for shorter.
REST API
Domains, accounts, mailboxes, messages, tokens. OpenAPI spec included.
Real-time Updates
New messages pushed via SSE. No polling.
Catch-All & Aliasing
Wildcard accounts and plus-sign addressing. Capture everything or route by tag.
FAQ
A hosted email sandbox: mail servers that accept your app's email and keep it instead of delivering it. Point a domain's MX record at it or send through send.smtp.dev, then read what arrived over IMAP, POP3, the REST API, or the web UI.
No. Mail sent through send.smtp.dev only reaches accounts in your sandbox, and any other recipient is refused, so a test can't email a customer by accident. For real delivery, use a service built for sending, like Amazon SES, SendGrid, or Postmark.
Yes. Sandbox domains have real MX records, so anything can deliver to them - a signup confirmation from a third-party service, an OTP, mail from your staging provider. Receiving is unrestricted; only what goes out is.
Only from the receiving end. Send from your server or provider to an address on your sandbox domain, and the message arrives with its raw source and SPF, DKIM, and DMARC results. It doesn't probe a server from outside, look up blocklists, or predict whether Gmail will file a message as spam. To check a server by hand, the SMTP test guide has swaks, curl, and openssl commands that work against any host.
Not a public one. There are no shared domains and no inboxes anyone can open. Addresses live on a domain you own, and each account has its own password. Tests can still create an address per run over the API and delete it afterwards.
Local catchers run per machine. The sandbox is hosted on real domains with real DNS, so CI, staging, and your laptop all hit the same MX path production will. Inbound messages also get SPF, DKIM, and DMARC verdicts, which localhost can't give you. The fake SMTP server comparison puts them side by side.
It puts addresses on your own domain, has no message quotas, and includes IMAP and POP3 on every plan. The comparisons list prices, limits, when to stay where you are, and how to move a test suite: Mailtrap, Mailosaur, Mailinator.
No. It's standard SMTP, IMAP, and POP3, plus a REST API described by an OpenAPI spec. Your existing mail library and HTTP client are enough.
Poll the REST API for new messages, or subscribe over SSE and react when one lands. The CI, Playwright, and AI agent guides have working examples.
SMTP on send.smtp.dev port 587, IMAP on imap.smtp.dev port 993, and POP3 on pop.smtp.dev port 995. The login is the account's full address and its password. The IMAP and POP3 guide has the commands for both.
Start testing
Sign up, add a domain, receive your first test email.