MailSlurp logo

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 Tutorial: Docker SMTP Capture, mhsendmail, and CI Email Testing article preview

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".

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:

  1. Subject, from, and reply-to values are correct.
  2. Dynamic tokens render correctly in HTML and text parts.
  3. Attachments and MIME boundaries are valid.
  4. 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:

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:

  1. Local: MailHog for fast iteration.
  2. PR/CI: API-driven integration tests against disposable inboxes.
  3. 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:

  1. Create a fresh inbox for the test run.
  2. Trigger the app action that sends the email.
  3. Wait for the message through the MailSlurp API.
  4. Assert the subject, recipient, link host, OTP value, attachment, or HTML marker.
  5. 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:

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.

Next steps