Every team that builds email features eventually faces the same fork: point development at a real SMTP provider, or fake the mail layer and hope production behaves. The first option leaks credentials, burns provider quota and occasionally emails a real customer from a laptop. The second tests nothing past the point where your code hands the message to a server. There is a better middle path — several, in fact. Here is how the standard local-testing options compare, and when each one wins.
Why real SMTP in development is a bad idea
The temptation is understandable: real provider, real behavior, zero setup. The costs appear later:
- Credential leakage. API keys that live in .env files on developer machines end up in logs, screenshots and eventually a chat thread.
- Accidental real sends. A test run against a copied production database emails real users from your laptop. This happens constantly, and it is always memorable.
- Flaky test suites. When unit tests depend on a third-party provider's uptime, rate limits and sandbox quirks, CI becomes weather forecasting.
- Cost and quota. Even generous free tiers drain fast when a test suite sends hundreds of messages per run.
The fix is to keep real sending out of the inner loop entirely — the reasoning in developers and QA testing with temporary email applies to local development too.
Option 1: catch-all local SMTP servers (MailHog, Mailpit)
A catch-all server listens on a local port, accepts everything without auth or TLS, stores messages in memory and shows them in a web UI. Your app points at it like any SMTP host:
SMTP_HOST=127.0.0.1 SMTP_PORT=1025
docker run -p 1025:1025 -p 8025:8025 axllent/mailpit
Mailpit is the current maintained standard: HTML preview, MIME parsing, a REST API for assertions and a chaos mode that simulates failures and delays. MailHog, its predecessor, has been unmaintained since 2020 but still works and still appears in countless tutorials; pick Mailpit for anything new.
Wins for: unit and integration tests, frontend work where designers need to see the emails, and laptops on trains with no network at all.
Option 2: container SMTP buckets in the dev stack
The next step up embeds the mail bucket in your docker-compose development stack as a named service with a persistent volume. Two things improve:
- Shared state. Every developer's mail lands in one predictable place, and restarting your app does not wipe the inbox.
- Test assertions via API. Mailpit exposes a REST API, so integration tests can fetch the last message sent to an address and assert on subject, headers and body without parsing logs.
The trade-off is unchanged: mail never leaves the machine. Authentication, DNS and actual deliverability remain untested, so a green suite can still ship a broken sender record. Before wiring staging to real domains, confirm the receiving side too — the MX checker shows the mail exchangers for any domain you are about to mail.
Option 3: disposable inboxes for staging realism
Local buckets cannot answer the question did the message actually arrive over the real internet. That question needs real delivery, which is where disposable inboxes earn their keep. Point staging at your real sending infrastructure and use temporary addresses as recipients: messages traverse genuine DNS, TLS and provider filtering, and you can assert on arrival time, content and spam-foldering — not just on your own outbound log.
This approach shines for:
- End-to-end signup flows. Verification links and one-time codes, asserted from the inbox side, with the automation pattern in temporary email API automation.
- Webhook pipelines. Bounce and inbound-message webhooks need real mail events to test; our guide to receiving email webhooks from a temporary inbox walks the wiring.
- Pre-production dress rehearsals. The fuller staging setup is covered in staging environment testing.
Which option when
- Local unit tests and preview: Mailpit on localhost. Fast, offline, zero side effects.
- Team dev environment: Mailpit as a compose service with a volume. Shared, inspectable, API-assertable.
- Staging and release verification: real sending plus disposable recipient inboxes. The only option that exercises the actual path your users' mail takes.
- Production monitoring: not a local topic at all — placement checks and seed tests take over there.
Treat these as layers, not competitors: most mature setups run all three, each at the altitude it is good at.
FAQ
Is MailHog still a good choice in 2026? It still works, but it has been unmaintained for years and lags on modern MIME handling. Mailpit is its actively developed successor with a compatible feature set — choose it for anything new.
Can I test DKIM and SPF with a local SMTP server? No. Authentication involves DNS and public-key lookups that a localhost server never exercises. Use real delivery to disposable addresses, then verify signatures on the received message.
How do I stop my dev environment from emailing real people? Point it at local SMTP, or use a staging flag that rewrites all recipients to disposable inboxes. Never keep production credentials on a dev-reachable path.
What is the cheapest way to assert an email arrived in CI? Create a temporary inbox via API, trigger the send, poll for the message and fail the build on timeout. It is a few lines of script and catches the failures local buckets cannot.
