blog
MailHog Tutorial: Docker SMTP Capture, mhsendmail, and CI Email Testing
Set up MailHog with Docker, capture local SMTP messages, test mhsendmail, and move release checks into MailSlurp inbox assertions.

MailHog is one of the fastest ways to test outbound email from a local app.
It runs a fake SMTP server, captures messages, and gives you a web UI plus HTTP API to inspect what your app sent.
Quick answer: when MailHog is the right tool
Use MailHog when you need:
- local SMTP capture during feature development
- safe testing without sending to real customers
- quick checks of headers, HTML, and attachments
Do not use MailHog alone when you need:
- shared team visibility across environments
- robust CI assertions for signup/reset flows
- deliverability confidence at real mailbox providers
MailHog in 60 seconds
MailHog listens on SMTP (default 1025) and stores intercepted messages.
You inspect mail in:
- Web UI (default
8025) - HTTP API for automated assertions
This is why developers search for terms like "MailHog Docker", "MailHog SMTP server", and "MailHog mhsendmail".
Docker setup (recommended)
version: "3.8"
services:
mailhog:
image: mailhog/mailhog:latest
ports:
- "1025:1025"
- "8025:8025"
restart: unless-stopped
Run:
docker compose up -d mailhog
Then configure your app to use:
- SMTP host:
localhost - SMTP port:
1025 - auth: disabled (for local testing)
Open MailHog UI at http://localhost:8025.
Testing sendmail apps with mhsendmail
mhsendmail is useful when your app expects a local sendmail binary.
It forwards messages to MailHog's SMTP endpoint so local mail never escapes to real recipients.
Example:
mhsendmail test@mailhog.local <<EOF
From: App <app@mailhog.local>
To: Test <test@mailhog.local>
Subject: Local MailHog test
This message should appear in MailHog UI.
EOF
What to validate in MailHog
Treat MailHog as a message quality gate for local work:
- Subject, from, and reply-to values are correct.
- Dynamic tokens render correctly in HTML and text parts.
- Attachments and MIME boundaries are valid.
- Links point to expected host/environment.
MailHog limitations teams hit later
| Limitation | Why it matters |
|---|---|
| Local process dependency | CI can become flaky if container lifecycle is not controlled |
| Shared-state friction | Hard to coordinate test visibility across multiple engineers |
| No real inbox/provider path | Cannot validate filtering, throttling, or mailbox placement |
MailHog vs hosted email testing
MailHog is excellent for local speed.
For release confidence, pair it with:
- Email Sandbox for disposable inbox workflows
- Email Integration Testing for app-level end-to-end checks
- Email Webhooks for event-driven assertions
- Email Deliverability Test for sender-quality monitoring
| Check | MailHog local capture | MailSlurp release check |
|---|---|---|
| SMTP submission | Confirm the app can hand a message to a local fake SMTP server | Confirm the app can send through the real staging or test path |
| Template content | Review subject, HTML, text, and attachments in the MailHog UI | Assert subject, body, links, attachments, and OTP values through API tests |
| Team visibility | Works best on one developer machine or a short-lived container | Shared inboxes, dashboards, webhooks, and test history for the team |
| Delivery evidence | Does not prove mailbox-provider behavior | Add headers, spam checks, inbox placement, and deliverability diagnostics |
CI handoff pattern that works
Use a staged workflow:
- Local: MailHog for fast iteration.
- PR/CI: API-driven integration tests against disposable inboxes.
- Pre-release: deliverability and sender policy verification.
This keeps developer feedback fast without shipping blind.
Move one MailHog test into CI
Start with a flow you already trust locally: signup confirmation, password reset, invoice receipt, or invite email.
In CI, replace the local MailHog recipient with a private MailSlurp inbox:
- Create a fresh inbox for the test run.
- Trigger the app action that sends the email.
- Wait for the message through the MailSlurp API.
- Assert the subject, recipient, link host, OTP value, attachment, or HTML marker.
- Store the message ID or webhook event with the failing test output.
That single migration catches the bugs MailHog cannot see: environment-specific sender configuration, broken links in staging, slow queues, incorrect recipients, and messages that never arrive in a real test inbox.
Create a MailSlurp test inbox when you are ready to move one local MailHog check into shared CI.
For broader coverage, use:
- SMTP Tester when you need a quick SMTP connection check.
- Email Header Analyzer when headers or authentication results look wrong.
- Email Webhooks when your tests should react to received messages.
- MailHog and Mailpit alternative when local SMTP capture no longer covers team or CI needs.
FAQ
Is MailHog still useful in 2026?
Yes, for local debugging, template checks, and fast SMTP capture while developing.
Can MailHog replace integration testing?
No. It captures local SMTP traffic but does not prove real receive-side behavior in production-like environments.
Is MailHog a Mailinator replacement?
Not directly. MailHog is local fake SMTP capture, while Mailinator-style tools focus on disposable inbox access.