MailHog was the default fake SMTP server for a decade: point your app at port 1025, open the web UI, read what it tried to send. The project has not shipped a release since 2020, so teams are moving. This page says where to, and it is candid that InboxDome is the right pick for only one of the two jobs MailHog did.
First decide which job you were using MailHog for
MailHog answered two different questions, and the best replacement differs for each:
- Did my code build and try to send the right message? Subject, body, recipients, template variables. A local catcher answers this. Nothing leaves your machine.
- Did the message actually arrive, and would a real mailbox accept it? SPF, DKIM, DMARC, the link in the mail, the verification code. Only a real receiving inbox on the public internet answers this, because the receiving server is the one that computes those results.
For local capture: Mailpit
Mailpit is the maintained successor to MailHog. It is a single binary, speaks SMTP on a local port, stores everything your app sends, and gives you a web UI and a REST API. It also adds what MailHog never had: an HTML compatibility check, a link checker and spam scoring. If your rule is that test mail must never leave your estate, this is the answer, and no hosted service, ours included, qualifies.
Moving from MailHog to Mailpit
- Replace the MailHog container or binary with Mailpit. The SMTP port stays 1025 by default.
- The web UI stays on port 8025 as well, so bookmarks and docker-compose port maps keep working.
- Tests that read the MailHog API (
/api/v2/messages) must change: Mailpit has its own API under/api/v1/. The shape is different, so this is the one real code change. - Delete the MailHog image. Nothing else in your app changes, because the SMTP side is identical.
For real delivery checks in CI: InboxDome
If what you want from a MailHog replacement is to see the mail a user would see, you are past what any catcher can do. InboxDome gives each test a real inbox on a real domain. Your app sends through your real provider, the message crosses the public internet, and the API hands the test the message, the verification code and the links, plus the SPF, DKIM and DMARC results the receiving side computed.
Moving a MailHog test to InboxDome
- Keep your app's SMTP configuration pointed at your real provider in the CI environment. Do not point it at a catcher.
- At the start of the test, create an inbox with one API call and use its address as the user's email in the signup or reset flow.
- Replace the MailHog poll with one
waitcall: it blocks until the message, the OTP or the link arrives, then returns it. - Assert on what you used to read from the MailHog JSON: subject, body, the link. The authentication results come for free.
- Delete the inbox at the end, or let it expire.
Step-by-step versions for Playwright,Cypress, GitHub Actions,Node, Python andPHP are in the guides. TheAPI page has the full flow.
What you lose, honestly
- A real inbox needs the network and a real sending domain. Tests that must run offline stay with Mailpit.
- Test messages really do get sent. Use a dedicated sending domain or stream for CI so a test burst never touches the reputation of your production mail.
- InboxDome is receive-only. It cannot reply, and it does not render a message in Outlook or Gmail for you.
Running both
Most teams end up with both: Mailpit in docker-compose for local work and unit-level tests, and a real inbox for the handful of end-to-end tests that must prove delivery, usually the signup, the password reset and the order confirmation. Thecomparison page sets the four approaches side by side, and theroundup of email testing tools covers the hosted sandboxes in between.