Email Testing

What is email sandboxing?

A sandbox catches the mail your application sends before it reaches anyone real. That makes most template bugs cheap to find, and makes a few delivery bugs impossible to see.

On this page
  1. Two different things get called an email sandbox
  2. How a capture sandbox actually works
  3. What a sandbox cannot show you
  4. Sandbox or real inbox, chosen per test layer
  5. Testing against a real disposable inbox
  6. The other sandbox, the one that clicks your links
  7. A setup that covers both

Email sandboxing means routing the mail your application sends into an isolated environment that captures it instead of delivering it. The message stops there. Nobody real receives it, and you get to open it and see exactly what your code produced.

Asking what is email sandboxing usually means one of two things, though, and mixing them up is how a team ends up with a green test suite and a broken signup flow in production.

Two different things get called an email sandbox

There are two honest answers to what is email sandboxing, and they point in opposite directions down the same wire.

The first is the testing sandbox: a fake mail server that accepts outbound mail from your app and holds it for inspection. Mailtrap sells exactly this under the name Email Sandbox, and Mailpit is a widely used self hosted equivalent that, in its own words, acts as an SMTP server with a web interface and an API for the captured mail.

The second is the security sandbox: the detonation chamber a mail gateway uses on incoming mail. Microsoft Defender for Office 365 opens attachments in a virtual environment before delivering them, a process its own documentation calls detonation. That one is not a testing tool at all, and it has a habit of breaking tests, which is the last section here.

How a capture sandbox actually works

If someone asks what is email sandboxing and means the testing kind, this is the entire mechanism, and there is no magic in it. You change the SMTP host, port and credentials your app uses:

MAIL_HOST=127.0.0.1
MAIL_PORT=1025

The sandbox speaks SMTP, accepts every message, stores it, and relays nothing onward. Mailpit listens on 1025 by default for precisely this. You then read the message back through a web UI while developing, or through the sandbox API inside an automated test.

The cheapest sandbox is not a server at all. Django ships four backends purely for this: console prints the message to stdout, filebased writes it to disk, dummy discards it, and locmem stores it in django.core.mail.outbox, which the test runner selects automatically. Rails, Laravel and Symfony all have an equivalent. If all you need is proof that one mail was queued to the right recipient, that is the whole job in zero infrastructure.

What a sandbox cannot show you

A capture sandbox proves your app tried to send something. It cannot prove the something would arrive. Three classes of bug live in that gap.

Authentication. SPF, DKIM and DMARC are evaluated by the receiving server against public DNS. A sink on localhost checks none of it, so a broken DKIM key or a missing DMARC record sails through every sandbox test you own. If that is unfamiliar territory, SPF, DKIM and DMARC explained covers what each one actually asserts.

Routing and reputation. MX lookups, TLS negotiation, greylisting, IP reputation and spam placement all happen after the point where the sandbox already said “accepted”.

Recipient side behaviour. Link scanners, image proxies and prefetchers touch your mail before the user does. Nothing on your laptop simulates that.

What a sandbox does catch is most of the everyday damage: an unrendered template variable, a hard coded staging URL in the reset link, the wrong locale, a zero byte attachment. That is the majority of email bugs by volume, which is why sandboxes are worth having at all.

Sandbox or real inbox, chosen per test layer

Pick by what the test asserts, not by preference:

  • Unit tests: the in memory backend. No network, no server, microseconds per test.
  • The local development loop: a self hosted sandbox like Mailpit, or a hosted one. Fast, offline, and no message can escape to a customer.
  • End to end and CI: a real address that receives over the public internet, because that is the only place delivery and authentication are real.

Being straight about it: for the inner loop, a local sandbox beats InboxDome. It runs offline, has no monthly quota, and nothing leaves your machine. Reach for a real inbox at the layer where the sandbox has stopped telling you anything new. The roundup of email testing tools compares the options in that middle band, and how Mailtrap captures test email walks through the classic hosted sandbox in more detail.

Testing against a real disposable inbox

At the end to end layer, the Email Testing API hands you a genuine inbox per test run, on a domain that resolves, with real MX records behind it:

# 1. a fresh inbox for this test
curl -X POST https://inboxdome.com/v1/inboxes \
  -H "Authorization: Bearer $INBOXDOME_KEY"

# 2. trigger your signup, then block until the code lands
curl "https://inboxdome.com/v1/inboxes/$INBOX_ID/wait?for=otp&timeoutSeconds=30" \
  -H "Authorization: Bearer $INBOXDOME_KEY"

# 3. or wait and assert in a single call
curl -X POST https://inboxdome.com/v1/inboxes/$INBOX_ID/assert \
  -H "Authorization: Bearer $INBOXDOME_KEY" \
  -H "Content-Type: application/json" \
  -d '{"timeoutSeconds":45,"assertions":[
        {"type":"otpPresent"},
        {"type":"auth","check":"dkim"},
        {"type":"auth","check":"spf"}]}'

Those auth assertions are the part a sandbox structurally cannot do. Inboxes are receive only, so nothing can ever be sent from one, and the free tier covers 100 inbox tests a month with no card. The code path is worked through step by step in testing OTP verification end to end, and the Playwright guide wires it into a browser suite.

Now the detonation kind, because it produces a support ticket you will otherwise misdiagnose. Gateways that scan inbound mail also follow the URLs inside it. If your verification or reset token is single use and consumed on GET, the scanner spends the token before your user clicks, and the user is told the link has expired.

Two fixes, both worth doing. Make the token consumable only on POST, so a GET renders a confirm page and burns nothing. And when you assert that a link works in a test, remember you are reproducing the same behaviour: a linkResponds assertion fetches the link server side and will consume a single use token exactly like a corporate scanner does.

A setup that covers both

Sandbox everything below end to end, so no environment is capable of mailing a customer by accident. Then run a smaller number of real inbox tests over the flows where the email is the product: signup, verification, password reset, receipts. A sandbox tells you the message is correct. Only a real inbox tells you it arrives, authenticated, in one piece.

Disclosure: InboxDome publishes this blog and makes the products it mentions. We describe what they do rather than promise results.

Key takeaways

  • Email sandboxing captures outbound mail in an isolated environment so it never reaches a real recipient.
  • A capture sandbox is usually a fake SMTP server: point your app at it, then read the message back over a web UI or an API.
  • A sandbox cannot tell you whether SPF, DKIM and DMARC pass, because nothing is ever evaluated against real DNS.
  • Use a local sandbox for the fast inner loop and a real receiving inbox for end to end and CI runs.
  • Security gateways run a second kind of sandbox that detonates attachments and follows links, which can burn single use tokens.

Sources

  1. Microsoft Learn: Safe Attachments in Defender for Office 365 — Describes opening attachments in a virtual environment before delivery, a process Microsoft calls detonation.
  2. Django documentation: email backends for development and testing — The console, locmem, filebased and dummy backends, none of which send anything.
  3. Mailpit: email testing tool and API — Acts as an SMTP server and provides a web interface plus an API for captured mail.
  4. Mailtrap developer documentation — Vendor documentation for their Email Sandbox product.

Links last checked September 3, 2026.

Frequently asked questions

Is email sandboxing the same as a spam filter sandbox?

No. A testing sandbox captures mail your own application sends so it never reaches anyone. A security sandbox opens incoming attachments and links in a virtual environment to look for malware before delivery. Same word, opposite direction of travel.

Can a sandbox test SPF, DKIM and DMARC?

Not meaningfully. Those checks run at the receiving server against public DNS records. A local SMTP sink accepts whatever it is handed, so you need a real inbox reachable over the internet to see real authentication results.

Do I still need a sandbox if I use disposable test inboxes?

Usually yes. A local sandbox is faster, works offline and costs nothing per message, which suits the inner development loop. Real inboxes earn their place in end to end and CI runs, where delivery and authentication actually matter.

How do I stop test mail reaching real customers?

Make the sandbox the default transport in every non production environment, set it from environment configuration rather than each developer remembering, and fail the build if production SMTP credentials appear in a non production config.

InboxDome TeamEmail infrastructure builders

The InboxDome team runs the temporary-email service and email-testing API this blog belongs to. We write about disposable inboxes, email privacy and testing transactional email, based on operating the infrastructure ourselves.