Why replace MailHog with Mailpit
MailHog was the go-to SMTP test server five years ago. But it has been unmaintained since 2020 and carries an unpatched stored XSS vulnerability (Exploit-DB 50971): any email containing JavaScript can compromise the web interface. Mailpit replaces it with a modern Go binary (under 50 MB RAM), a clean interface, full-text search, a documented REST API, an HTML compatibility report, and built-in spam scoring. It ships as the default in Laravel Sail since version 11 and in DDEV since version 1.22, making it the new industry standard.
What Mailpit brings in practice
- SMTP capture on port 1025 — no email ever leaves your VPS, just configure your app to use localhost:1025.
- Web interface on port 8025 with full-text search across subject, sender, and body.
- REST API GET /api/v1/messages — query emails from your integration tests without any external relay.
- Spam scoring with SpamAssassin rules — catch deliverability issues before production.
- HTML compatibility report — spot CSS properties that will be stripped by Gmail, Outlook, or Apple Mail.
- Mobile preview and raw source view, with full HTML rendering and detailed headers.
- POP3 interface to fetch captured emails with any mail client.
- SQLite on a persistent volume — messages survive container restarts.
Deployment architecture on a VPS
Mailpit runs in a single Docker container. The SMTP server is accessible on localhost:1025 (loopback only), meaning only applications running on the same VPS can send emails to it — exactly what you want. The web interface is exposed on localhost:8025 and then proxied by nginx to a domain of your choice. This pattern is identical to Node-RED, Plausible, or Umami: one container, one loopback port, one nginx domain, one persistent volume.
Deploy Mailpit in 5 steps
Deploy from the ServOrbit marketplace
Open your control panel, go to Marketplace → Development → Mailpit and click Deploy. The container starts in under ten seconds.
Configure your application SMTP
In your environment variables, set MAIL_HOST=127.0.0.1 and MAIL_PORT=1025. No authentication, no TLS required by default. Laravel, Symfony, Django, Node.js — all support this configuration natively.
Open the web interface
Navigate to the domain attached to your Mailpit instance. You will see the real-time inbox: click any email to inspect its HTML rendering, headers, and spam score.
Integrate the REST API into your tests
Call GET https://mailpit.your-domain.com/api/v1/messages from your test suite. Filter by recipient, verify the subject, count attachments — all without mocks or stubs.
Check HTML compatibility
Open any HTML email and click the Compatibility tab. Mailpit lists unsupported CSS properties client by client, with links to recommended fixes.
Mailpit in CI/CD: testing emails in the pipeline
Deploy Mailpit as a service in your test docker-compose.yml (image: axllent/mailpit:latest, ports: 127.0.0.1:8025:8025 and 127.0.0.1:1025:1025). Your integration tests send emails to localhost:1025, then verify via the REST API that the correct message was received. This pattern is used by Laravel, Symfony, and Django teams to validate notifications and transactional emails without an external relay.
Mailpit vs MailHog vs Mailtrap
| Maintainer | Axle Springer (active) | Abandoned since 2020 | Mailtrap Inc. (SaaS) |
| Security | No known vulnerabilities | Unpatched stored XSS | SaaS — data hosted elsewhere |
| REST API | Complete and documented | Basic, undocumented | Yes (paid plan) |
| Spam scoring | Built-in (SpamAssassin) | None | Yes (paid plan) |
| HTML compatibility | Built-in report | None | Yes (paid plan) |
| Price | Free, MIT | Free, MIT | Freemium, then $24/month |
| Self-hosting | One Docker container | One Go binary | SaaS only |
Advanced use cases
Beyond simple send testing, Mailpit offers several lesser-known features. Multi-tenant mode (--mp-tenant) separates emails by application in a single server. SMTP authentication (MP_SMTP_AUTH_FILE) restricts who can connect. The MP_UI_AUTH_FILE variable adds basic auth to the web interface if you expose it publicly. And configurable retention (MP_MAX_MESSAGES=0 for unlimited, or a specific number) lets you adjust the retention policy to your testing needs.