MailHog intercepts SMTP traffic locally, letting you inspect unsent emails before they hit real inboxes.

Let’s see it in action. Imagine your web application needs to send a welcome email upon user signup. Instead of configuring a real SMTP server that might clutter your test users’ inboxes or require complex credentials, you’ll point your application’s SMTP settings to MailHog.

Here’s a typical configuration snippet you’d find in an application’s .env file or configuration service:

MAIL_DRIVER=smtp
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls

When your application code executes the email sending logic, it attempts to connect to localhost:1025. MailHog is listening on this port. It receives the email data (sender, recipient, subject, body, attachments) and stores it in its internal memory. You then open a web browser to http://localhost:8025 (MailHog’s web UI) and see the email listed. Clicking on it reveals its full content, headers, and any attached files, exactly as it would have been sent.

MailHog solves the problem of needing to test email functionality in development or staging environments without the overhead and potential side effects of using a live email service. It provides a safe, isolated sandbox for email.

Internally, MailHog is a Go application that acts as both an SMTP server and an HTTP server. When it starts, it binds to a specified SMTP port (default 1025) and an HTTP port (default 8025). The SMTP server listens for incoming connections from your application, parses the MAIL FROM, RCPT TO, and DATA commands according to the SMTP protocol, and collects the email content. The HTTP server provides the web interface where you can view the collected emails. It also exposes an API, allowing automated tests to query for emails and assert their content programmatically.

The levers you control are primarily the host and port your application points its SMTP client to. By default, MailHog runs on localhost:1025 for SMTP and localhost:8025 for its web UI. You can configure MailHog to listen on different ports if 1025 or 8025 are already in use, or if you need to run multiple instances. You can also configure MailHog to relay emails to a real SMTP server if you need to test the actual delivery path while still having a fallback inspection point, though this is less common for pure development testing.

The API endpoint /api/v1/messages is incredibly useful for integration tests. You can make a GET request to this endpoint after triggering an email send and programmatically verify that the correct email was received by MailHog, checking its subject, body content, and recipient without needing to parse HTML or manually inspect the UI. This allows for robust, automated email testing that’s fast and reliable.

You can also easily delete all collected emails via the web UI or the /api/v1/messages endpoint to start with a clean slate, which is essential for running repeatable test suites.

If you ever need to simulate an SMTP server that rejects connections or sends specific error codes back to the client, MailHog doesn’t directly support this level of granular SMTP protocol manipulation.

Want structured learning?

Take the full Smtp course →