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
Any mail client or library connects with its standard settings. No SDK to install.
Inspect received email
Check what arrived in the UI or wire it into CI.
- Delivery checksHTML preview, plain text, headers, and raw source. SPF, DKIM, and DMARC results come over the API.
- CI-readyAny CI that can send over SMTP works, including GitHub Actions, Jenkins, and GitLab CI.
- Deliverability auditSender config, HTML structure, links, and the content patterns spam filters flag. Grouped by severity.
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
No daily caps and no metering on any plan.
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, such as a signup confirmation from a third-party service, an OTP, or mail from your staging provider. Receiving is unrestricted. Only outbound mail is limited.
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.