Fake SMTP server for development and testing
A fake SMTP server accepts email over the standard SMTP protocol, stores each message for inspection, and never relays anything to a real recipient. Your application connects, authenticates, and sends exactly as it would in production, but every email lands in a capture inbox instead of a customer's mailbox.
Fake SMTP servers at a glance
| Tool | Hosting | Cost | Maintained |
|---|---|---|---|
| Mailpit | Self-hosted (Go binary or Docker) | Free, MIT license | Yes, active |
| smtp4dev | Self-hosted (.NET or Docker) | Free, BSD license | Yes, active |
| Mailloop | Hosted (sandbox.mailloop.io) | Free plan: 1 sandbox, 500 emails/mo, then from $12/mo | Yes |
| MailHog | Self-hosted (Go binary or Docker) | Free, MIT license | No, abandoned since 2020, use Mailpit |
Why not just send through your real provider?
Sending test email through your real provider risks delivering unfinished messages to real customers and feeding bounces and spam complaints from test runs into your production sending reputation. The classic version: a staging database gets seeded from a production dump, someone re-enables the reminder cron job to test it, and a few thousand customers get a half-finished email with a broken staging link on a Saturday morning. A fake SMTP server makes that mistake structurally impossible. The mail is accepted, stored, and goes nowhere, no matter what addresses are in the database. It also keeps test traffic off your sending domain entirely.
How does SMTP capture actually work?
A fake SMTP server completes the normal SMTP conversation (220 greeting, EHLO, MAIL FROM,
RCPT TO, DATA) but writes the message to storage instead of relaying it to the recipient's
mail server. There is no trick on the client side: the fake server listens on a TCP port
and plays the server half of the protocol, answering 250 at every step and accepting
the message after DATA. Your application gets a success response and cannot
tell the difference.
220 sandbox.mailloop.io ESMTP server greets your app
EHLO app.example.com
250-sandbox.mailloop.io capability list follows
250-AUTH LOGIN PLAIN
250 STARTTLS
AUTH LOGIN
235 Authentication successful
MAIL FROM:<[email protected]>
250 OK
RCPT TO:<[email protected]>
250 OK accepted, never relayed
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: Reset your password
...headers and body...
.
250 OK stored in the inbox instead
QUIT
221 Bye
That last 250 OK after the message body is the whole product. A real server would
now queue the message for delivery to [email protected]. The fake one parses
it, stores it, and shows it to you in a web inbox or over an API.
Should you self-host a fake SMTP server or use a hosted one?
Self-host a free tool like Mailpit when you test alone on a single machine; pick a hosted sandbox when a team, a staging environment, a CI pipeline, or an AI agent needs to reach the same inbox without extra infrastructure.
Self-hosted: Mailpit and smtp4dev
For testing on a single machine, the self-hosted tools are genuinely good and cost nothing. Mailpit is a single Go binary with no runtime dependencies: SMTP on port 1025, web UI on 8025, a REST API you can assert against, and active maintenance (it is the successor Laravel Sail and DDEV adopted after MailHog was abandoned). smtp4dev is the .NET equivalent with a web UI, IMAP and POP3 access, and a Swagger-documented API. If your whole workflow is "run the app locally, look at the email", run Mailpit in Docker and you are done.
The self-hosted model gets awkward when more than one machine is involved. A teammate cannot open the inbox running on your laptop. CI needs a service container wired up per pipeline. Staging needs the tool deployed, secured, and kept up to date. Spam scoring in Mailpit requires running a separate SpamAssassin server. Each problem is solvable; they just add up to infrastructure you maintain for a debugging tool.
Hosted: Mailloop
Mailloop is a hosted fake SMTP server at sandbox.mailloop.io, listening on
ports 25, 465, 587, and 2525. Each sandbox has its own SMTP credentials and a shared web
inbox, so local dev, staging, CI, and every teammate point at the same place with nothing
to deploy. Captured email is readable through the REST API at
api.mailloop.io and the @mailloop/sdk npm package for automated assertions,
webhooks can push new messages to your test harness, and the inbox includes spam and deliverability
checks plus email screenshots. When a message needs to reach an actual mailbox (a designer checking
rendering in real Gmail), you can resend it to a verified real address. AI coding agents get
the same access through an OAuth MCP server at https://api.mailloop.io/mcp and
agent skills at
github.com/mailloop/skills.
Which one fits your setup?
| Concern | Self-hosted (Mailpit, smtp4dev) | Hosted (Mailloop) |
|---|---|---|
| Cost | Free (MIT / BSD), your infrastructure | Free plan: 1 sandbox, 500 emails/mo. Paid from $12/mo |
| Setup | Run a binary or Docker container per environment | Change SMTP host and credentials, nothing to run |
| Team access | Inbox lives on one machine unless you network it | Shared web inbox per sandbox |
| CI | Service container per pipeline, wire ports and env vars | Point tests at sandbox.mailloop.io, assert via API or SDK |
| Spam scoring | Mailpit needs a separate SpamAssassin server; none in smtp4dev | Built-in spam and deliverability checks |
| AI agent access | Third-party MCP for Mailpit only, none for smtp4dev | Hosted OAuth MCP server, no key to paste |
| Maintenance | You patch, upgrade, and secure it | None |
Solo developer testing locally: use Mailpit. Team, staging, CI, or AI agents that need to read email: use a hosted sandbox like Mailloop.
One tool to avoid for new projects: MailHog. It has had no release since 2020, ships an unpatched stored XSS in its web UI, and only accepts unencrypted connections. Mailpit is the drop-in replacement.
If you are weighing hosted services against each other, see Mailtrap alternatives compared side by side and our roundup of the best email testing tools in 2026. Related: what an email sandbox adds on top of raw SMTP capture, and how to wire email testing into coding agents with the Mailloop MCP server.
How do I point Nodemailer, Laravel, Django, or Rails at a fake SMTP server?
Point any framework at a fake SMTP server by changing four environment values, the SMTP
host, port, username, and password; no application code changes are needed because the
fake server speaks standard SMTP. The examples below use Mailloop; for a local Mailpit,
replace the host with localhost and the port with 1025. Port 587
uses STARTTLS, 465 uses implicit TLS, and 25 and 2525 also work if your network blocks the
others.
Nodemailer (Node.js)
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'sandbox.mailloop.io',
port: 587, // also works on 25, 465, and 2525
secure: false, // set true for port 465
auth: {
user: 'your-sandbox-username',
pass: 'your-sandbox-password',
},
}); Laravel (.env)
MAIL_MAILER=smtp
MAIL_HOST=sandbox.mailloop.io
MAIL_PORT=587
MAIL_USERNAME=your-sandbox-username
MAIL_PASSWORD=your-sandbox-password
MAIL_ENCRYPTION=tls Django (settings.py)
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'sandbox.mailloop.io'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'your-sandbox-username'
EMAIL_HOST_PASSWORD = 'your-sandbox-password'
EMAIL_USE_TLS = True Rails (Action Mailer)
# config/environments/development.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'sandbox.mailloop.io',
port: 587,
user_name: 'your-sandbox-username',
password: 'your-sandbox-password',
authentication: :plain,
enable_starttls_auto: true
}
Mailloop captures by SMTP authentication, not by recipient: whatever address is in the
To field, the message lands in the sandbox that owns the credentials. That is what
makes the production-dump scenario safe.
Frequently asked questions
Can't find what you're looking for? Email our team →