MailHog was the default answer for years: run one container, point your application at port 1025, read the captured mail on port 8025. It still works, and plenty of docker-compose.yml files still carry it — but it is no longer maintained, and Mailpit's own README says so in as many words: MailHog “is no longer maintained and hasn't seen active development or security updates for a few years now”. For a tool that parses untrusted MIME produced by your own application, the missing security updates are the part that matters.
The good news is that its successor listens on the same two ports, so for most projects this is a five-minute change in a compose file.
What MailHog did, and why its age matters
MailHog did three things well: it spoke SMTP (port 1025), it showed captured messages in a web UI (port 8025), and it exposed a JSON API so tests could read them. It also offered in-memory storage with optional MongoDB or file persistence, a mhsendmail replacement for PHP, live updates over EventSource and a chaos feature for failure testing.
None of that is broken. The problem is what happens around an unmaintained dependency:
- No security updates. MIME parsing is exactly the kind of code that receives CVEs, and a catcher accepts mail from anywhere — a staging instance reachable from the internet is a service, not a toy.
- Container images stop being rebuilt. Your pinned tag keeps working until the base image or the platform underneath it moves on.
- The ecosystem moved. Mailpit (Go, single binary) became the direct successor, smtp4dev covers the .NET and Windows side, Mailcatcher and MailDev cover Ruby and Node — all actively developed.
- Small features that save time (search, checks, pruning, POP3) exist only in the successors.
What to use instead
| Tool | What it is | Why pick it |
|---|---|---|
| Mailpit | Go, single binary or container, actively developed | the closest thing to a drop-in replacement: same defaults, plus a REST API, HTML/link/spam checks, optional POP3, live web sockets and pruning |
| smtp4dev | .NET, binary or container | Windows-first teams and .NET stacks |
| Mailcatcher (Ruby) / MailDev (Node) | run inside your own toolchain | when you want the catcher as a gem or an npm dependency |
| This instance | hosted privately by its operator | nothing to run or maintain, SMTP and webhooks on one address, share links and a JSON export for scripts and AI assistants |
| Commercial sandboxes | vendor-hosted | teams that need SSO, shared inboxes, support and an SLA |
Migrating from MailHog to Mailpit
Mailpit's defaults match MailHog's: SMTP on 1025, UI on 8025. In Docker Compose the change is the image name (and the volume path, if you mounted one) — the port mappings stay as they are, and your application configuration does not change at all, because it only knows a host and a port.
Three details differ once you are past the image tag:
- Environment variables are prefixed
MP_instead ofMH_. If you set MailHog's storage options, translate the two or three you actually use; if you never set any, there is nothing to do. mhsendmailbecomesmailpit sendmail, used the same way inphp.inior any other sendmail configuration.- Storage is a single data file (or memory), not MongoDB. If you relied on the Mongo backend to keep mail across restarts, that is the one thing to plan for.
Keep the old container commented out for a day, so going back costs one line.
What you gain and what you lose
Gained: active maintenance, a modern UI with search, HTML, link and spam checks, optional POP3 to pull captured mail into a real client, live updates over web sockets, a REST API for assertions, and automatic pruning (by default it keeps the most recent 500 messages) so a long-running instance does not grow forever. Mailpit also keeps a sendmail replacement and a chaos feature for testing SMTP failures.
Lost: MongoDB-backed storage. Everything else MailHog did — SMTP on 1025, UI on 8025, JSON API, persistence, failure testing — has an equivalent.
If you would rather not run anything at all
MailHog and Mailpit are services you own: a container, a volume, an upgrade path and somebody who notices when it stops. This instance is a different trade-off — SMTP and webhook capture on one address, no metering, nothing to maintain, with read-only share links and a JSON export so scripts and AI assistants can read the captured mail. It is not self-hostable, and that is exactly the point: if self-hosting is a hard requirement, run Mailpit.
Next steps
- Mailtrap alternatives: free, open-source and self-hosted options — the wider comparison, commercial sandboxes included.
- How to test email sending without sending anything — the four-step setup that works with Mailpit, smtp4dev and this instance alike.
- How to test webhooks locally without ngrok — the same problem for callbacks instead of mail.
- Limits of this instance — sizes, retention and quotas in one table.