
local email testing for ai agent development: a practical setup guide
Compare Mailpit, MailHog, Mailtrap, and agent-first APIs for local email testing in AI agent projects. Step-by-step setup, zero DNS required.
You're three hours into building an agent that sends confirmation emails. The logic works. The prompt is solid. But every test run burns a real send against Gmail's rate limits, and you've already hit the "unusual activity" wall twice today.
This is a familiar trap. Your agent's email logic needs a feedback loop that's fast, private, and free from production side effects. Local email testing gives you that by intercepting outbound messages before they reach real inboxes, letting you inspect headers, verify MIME structure, and trigger agent workflows without delivering a single real message.
This guide compares the main local testing tools for agent email, walks through setup, and covers where SMTP interceptors fall short for agent-specific workflows. If you'd rather skip the infrastructure side, with no configuration at all.
How to set up local email testing for AI agent development#
- Install a local SMTP interceptor such as Mailpit:
docker run -p 1025:1025 -p 8025:8025 axllent/mailpit. - Set
SMTP_HOST=localhostandSMTP_PORT=1025as environment variables in your project. - Point your AI agent's email client or SDK at those variables.
- Trigger a test send from your agent's workflow.
- Open the Mailpit web UI at
localhost:8025to inspect captured messages. - Validate headers, HTML rendering, and MIME structure visually.
- Add the interceptor as a service container in your CI/CD pipeline for automated regression testing.
Each step takes under a minute. The entire process, from install to first captured email, runs in about five minutes on a fresh machine.
Comparing local email testing tools#
Four tools show up in almost every discussion about testing email locally. Here's how they compare when you're building an AI agent:
| Tool | Type | API | Inbound simulation | Best for |
|---|---|---|---|---|
| Mailpit | Self-hosted SMTP | REST API | None | Fast local capture with a clean web UI |
| MailHog | Self-hosted SMTP | REST API | None | Lightweight Go-based interceptor |
| Mailtrap | Cloud sandbox | REST + SMTP | Limited | Teams sharing test inboxes across environments |
| Ethereal | Disposable SMTP | None | None | Quick throwaway tests with Nodemailer |
All four catch outbound email reliably. Point your agent at localhost:1025 (or Mailtrap's cloud SMTP credentials), and every message your agent sends lands in a test inbox instead of a real recipient's mailbox.
Mailpit is my default recommendation for most projects. It's actively maintained, starts in under a second, and its REST API lets you programmatically verify that your agent sent the right content. MailHog works too, though it hasn't seen significant updates recently. Mailtrap is the best option if your team needs shared visibility into test emails across multiple developers.
Ethereal is useful in exactly one scenario: you're using Nodemailer, you need a throwaway test account, and you don't want to install anything. For everything else, Mailpit gives you more control.
Where SMTP interceptors fall short for agents#
If your agent only sends email, a local SMTP interceptor handles everything. Install Mailpit, set two environment variables, run your agent, check the web UI. Done.
The gap shows up when your agent also needs to receive email. Think about common agent workflows that depend on inbound mail:
- Sign up for a service, wait for a verification code, extract it, continue
- Monitor an inbox for incoming support tickets and generate responses
- Parse inbound receipts or shipping notifications and update a database
Local SMTP interceptors don't model inbound delivery. There's no way to programmatically drop an email into a test inbox and have your agent pick it up through a receive call. You'd need to mock the entire receive path yourself, which means your tests never exercise the real email retrieval logic.
Webhook simulation has the same problem. If your agent triggers actions when new email arrives via webhooks, you need a way to fire those events locally. Tools like ngrok can expose a local endpoint to the internet, but now you depend on external infrastructure and real inbound email to test what should be an isolated local workflow.
We covered this gap in more detail in our guide to testing agent email without hitting production.
Programmatic inboxes: the missing piece#
The pattern most agent developers actually need is: spin up a temporary inbox in code, send or receive through it, inspect the results. No DNS records, no domain verification, no OAuth dance.
This is where agent-first email APIs differ from SMTP interceptors. Instead of capturing traffic at the transport layer, they give your agent a real inbox it can provision itself:
import { LobsterMail } from '@lobsterkit/lobstermail';
const lm = await LobsterMail.create();
const inbox = await lm.createSmartInbox({ name: 'Test Agent' });
console.log(inbox.address); // test-agent@lobstermail.ai
// Your agent can now send AND receive through this address
const emails = await inbox.receive({ timeout: 30000 });
No SMTP configuration. No Docker container. No DNS setup. The agent provisions its own inbox programmatically and starts using it immediately. This is the core idea behind agent self-signup: why the agent should create its own inbox.
The LobsterMail free tier includes 1,000 emails per month at no cost, which covers most development and testing cycles. If you're running heavier test suites or need up to 10 inboxes, the Builder plan at $9/month handles that.
Tip
createSmartInbox() generates a human-readable address from your agent's name and handles collisions automatically. For disposable test inboxes where the address doesn't matter, createInbox() is faster and returns a random lobster-xxxx@lobstermail.ai address.
Toggling between local and production config#
A clean setup uses environment variables so you can switch between local SMTP testing and a production API without touching code:
# .env.local (development with Mailpit)
EMAIL_PROVIDER=smtp
SMTP_HOST=localhost
SMTP_PORT=1025
# .env.production (agent-first API)
EMAIL_PROVIDER=lobstermail
LOBSTERMAIL_TOKEN=lm_sk_live_...
Your agent's email module reads the provider flag and routes accordingly. In CI, run Mailpit in a service container for outbound-only tests and hit the LobsterMail API for inbound receive tests. Every commit runs through both paths without any manual switching.
The most common mistake I see in the wild: hardcoding SMTP credentials directly in the agent's config instead of using environment variables. When someone forgets to swap them before a demo, the agent blasts test content to real recipients. Environment variables eliminate that risk entirely.
<Callout type="warning">
Never commit `.env` files with production tokens to version control. Use `.env.local` for development values, `.env.production` for deploy-time injection, and add both to `.gitignore`.
</Callout>
## Writing testable agent email logic
Beyond infrastructure, code structure matters. Isolate your agent's email logic into functions that accept an email client as a parameter rather than importing a global client:
```typescript
async function handleVerificationFlow(emailClient, serviceUrl) {
const inbox = await emailClient.createSmartInbox({ name: 'Verify' });
await signUpForService(serviceUrl, inbox.address);
const emails = await inbox.receive({ timeout: 30000 });
const code = extractVerificationCode(emails[0].body);
return code;
}
In tests, pass a mocked client that returns predetermined email objects. In production, pass the real LobsterMail client. The logic under test stays identical either way.
This pattern also makes it straightforward to test edge cases. What happens when receive() returns zero emails? What if the verification code is buried in HTML rather than plain text? What if the email body contains a prompt injection attempt? You can simulate all of these with mock data, no real email delivery required. LobsterMail also scores inbound messages for injection risk automatically (see the security docs for details on how that works).
A practical testing stack for 2026#
For most agent projects, here's the combination I'd recommend:
- Mailpit for catching outbound email during local development. Starts instantly, clean web UI, REST API for automation.
- LobsterMail free tier for testing inbound workflows. Your agent provisions real inboxes programmatically with no DNS required.
- Mocked email clients for unit tests. Fast, deterministic, zero network calls.
- CI integration running Mailpit as a service container alongside LobsterMail API calls for end-to-end receive tests.
This covers outbound capture, inbound simulation, unit isolation, and automated regression. It's also free for small teams: Mailpit is open source, and LobsterMail's free tier costs nothing.
Pick the layer that matches your test. Don't spin up a Docker container when a mocked client will do. Don't mock when you need to verify real delivery behavior. Match the tool to the question you're actually asking.
Frequently asked questions
What is local email testing and why does it matter for AI agent development?
Local email testing intercepts outbound messages before they reach real recipients, letting you inspect content, headers, and delivery behavior in a safe environment. For AI agents, this prevents burning production rate limits, leaking test data to real people, and triggering spam filters during development.
How do I install and configure Mailpit as a local SMTP interceptor?
Run docker run -p 1025:1025 -p 8025:8025 axllent/mailpit and set your agent's SMTP host to localhost port 1025. Captured emails appear in the web UI at localhost:8025. You can also install via Homebrew with brew install mailpit if you prefer running it natively.
Which environment variables should I set to route my agent's email to a local test server?
Set SMTP_HOST=localhost and SMTP_PORT=1025 for Mailpit's defaults. Store these in a .env.local file so they don't leak into production. Your agent's email module should read these values at runtime instead of hardcoding them.
How can I programmatically spin up a temporary inbox without DNS records or domain verification?
Use an agent-first email API like LobsterMail. Call createSmartInbox({ name: 'My Agent' }) to provision a working @lobstermail.ai inbox in milliseconds with no DNS, domain verification, or OAuth required. The free tier covers 1,000 emails per month.
What is the difference between SMTP-based local testing and an agent-first REST email API?
SMTP interceptors like Mailpit capture outbound mail at the transport layer. REST email APIs like LobsterMail provision full inboxes your agent can send from and receive into programmatically. Use SMTP tools for outbound-only testing and APIs when your agent also needs to receive or poll for email.
How do I simulate incoming emails locally to trigger my agent's decision logic?
Local SMTP interceptors can't simulate inbound delivery. Use a real inbox from an agent-first API instead: your agent calls receive() to poll for new messages, or registers a webhook that fires when email arrives. Both approaches work without exposing a local server to the internet.
Can I test inbound email webhooks locally without exposing my server to the public internet?
With pure SMTP tools, no. You'd need a tunneling service like ngrok. With LobsterMail, your agent can poll for email using receive() instead of relying on inbound webhooks, which removes the need for public endpoint exposure during local development entirely.
How do I write unit tests for AI agent email logic that run without sending real messages?
Inject the email client as a parameter to your email functions instead of importing a global instance. In unit tests, pass a mocked client that returns predetermined email objects. This tests your agent's parsing and decision logic without any network calls.
What are the privacy advantages of keeping email test data fully local versus using a cloud sandbox?
Local tools like Mailpit keep all captured email on your machine. Nothing leaves your network. Cloud sandboxes like Mailtrap or AgentMail's free tier store captured emails on external servers, which may matter if your agent processes sensitive content or you have data residency requirements.
How do I integrate local email testing into a CI/CD pipeline?
Run Mailpit as a service container in your CI environment (most CI platforms support Docker services natively). Set the SMTP environment variables in your CI config. For inbound tests, use the LobsterMail API with a test-mode token. Your test suite exercises both send and receive paths on every commit.
Is the AgentMail free tier sufficient for local AI agent development and testing?
AgentMail's free tier offers 3 inboxes and 3,000 emails per month, which works for light testing. LobsterMail's free tier provides 1,000 emails per month with automatic inbox provisioning and no credit card. For more inboxes or volume, LobsterMail's Builder plan at $9/month covers up to 10 inboxes and 5,000 emails.
How do I toggle between local test config and production email config without code changes?
Use a provider flag in your environment variables (EMAIL_PROVIDER=smtp for local, EMAIL_PROVIDER=lobstermail for production). Your agent's email module reads this flag and routes to the correct backend. Switch contexts by swapping .env files, not source code.
What are the most common errors when setting up local email testing for AI agents?
The top three: hardcoding SMTP credentials instead of using environment variables (causes accidental production sends), forgetting to start the local SMTP server before running tests (connection refused errors), and not handling the case where receive() returns an empty array (agent crashes on missing email).
Which Node.js libraries work best for local email testing in AI agent projects?
Nodemailer pairs well with Ethereal for quick throwaway tests. For more control, use Mailpit with its REST API and fetch to query captured messages programmatically. The @lobsterkit/lobstermail SDK handles both sending and receiving if you want a single library for the full workflow.
How do I test email attachments and HTML rendering locally with an AI agent?
Mailpit and MailHog both render HTML emails in their web UIs for visual inspection. For automated checks, Mailpit's REST API returns attachment metadata including file names, MIME types, and raw content, letting you verify attachments programmatically in your test suite.


