How Do You Test a Bot's Email Routine Without Spamming Real Inboxes?
A bot that sends email can't be tested the way you test a read-only tool: every bad run either spams a real inbox or silently does nothing. Provider sandbox modes validate the request without delivering it, but they don't prove the email would have looked right or arrived. The fix is layering two checks: a provider sandbox for request validation, and a dedicated test account for a real end-to-end send.
AI-assisted editorial: researched and drafted with AI using the primary sources linked below. Examples are illustrative; they are not measured product results. Editorial policy.
Key takeaways
- SendGrid sandbox mode validates request form, type, and shape without delivery. Mailgun test mode accepts a message without sending it; its documentation does not promise the same validation scope. Neither proves template rendering or inbox arrival.
- A dedicated test mailbox is the only way to confirm a send actually renders and arrives; treat it as production scoped to an inbox nobody depends on.
- Test the bot's decision to send, not just the send call: assert it chose the right recipient and template before the message ever reaches a transport layer.
Why you can't test email sending like you test a read call
A bot that reads a calendar or queries a database can be tested against a disposable fixture and thrown away. A bot that sends email has a side effect that leaves your control the moment the transport layer accepts the request. Run the test suite twice against a live sending account and you've emailed someone twice. Run it against a bad test double and you might convince yourself the bot works when the real API would have rejected the payload.
The failure mode that matters for an email-sending routine isn't just 'did it crash' — it's 'did it send the right thing to the right person, and would a real send have gone through.' Those are two different questions, and no single test environment answers both.
What sandbox mode actually checks
SendGrid's Mail Send API has a sandbox_mode setting inside mail_settings. With it enabled, the API validates the structure of your request and returns a 200 OK — but the email is never delivered, and the call doesn't consume your sending quota. SendGrid's own documentation is explicit about the boundary: sandbox mode is only used to validate your request, and the email will never be delivered while this feature is enabled.
Mailgun offers the same shape of guarantee through a different mechanism: set o:testmode to yes or true and Mailgun will accept the message but will not send it. Both providers are describing the same class of check — confirm the API call is well-formed, not that a human would ever see the result.
This matters for a bot because it separates two things your test suite would otherwise conflate: whether the bot constructed a valid request, and whether that request would have reached someone. Sandbox mode only answers the first question.
Sources: Sandbox Mode, Sending Messages in Test Mode.
What sandbox mode won't catch
Sandbox mode checks shape, not substance. SendGrid's documentation notes that if your request includes a template_id, sandbox mode assumes a subject line and body are present inside the template but does not validate that content. So a bot that sends a digest email with an empty or malformed template body can pass sandbox validation every time and still produce a blank email in production.
Sandbox mode also can't tell you whether the recipient address your bot picked was correct, whether the message would have landed in spam, or whether a retry after a timeout produced a duplicate send. Those failures live in the bot's own logic and in the gap between 'accepted' and 'delivered' — a gap sandbox mode is explicitly designed not to cross.
Sources: Sandbox Mode.
Worked example: testing a weekly digest bot
Say a bot compiles a weekly summary of open tasks and emails it to a team lead every Monday. This is illustrative, not a specific product. The test plan has three layers, and each one catches a different failure.
Layer one uses the provider's non-delivery mode with real API credentials. SendGrid sandbox mode checks the request's form, type, and shape; Mailgun documents that test mode accepts a message without sending it, but does not describe an equivalent field-by-field validation guarantee. Inspect provider responses and assert the bot's intended recipient and template variables separately. This layer cannot prove that a rendered message would arrive.
Layer two runs against a dedicated test mailbox the team owns, with sandbox mode off. This is the only way to confirm the digest actually renders: do the task counts match what's in the source system, does the template fallback text read correctly, does the message arrive at all within a reasonable window. Treat this account exactly like production — because for the provider, it is — just scoped to an inbox nobody depends on for real work.
Layer three never touches a transport layer at all. It asserts on the bot's decision before the send: given a fixture with three overdue tasks and one completed task, does the bot pick the correct recipient, does it skip sending if there's nothing overdue, and does it log what it intended to send even if the provider call is mocked out entirely. This layer is cheap to run on every commit and catches the logic bugs that sandbox mode structurally cannot see.
A bot that passes layer one but has never run layer two has only proven it can talk to the API, not that anyone would recognize the email it sends.
The decision for your bot
Use sandbox or test mode for automated runs that do not need inbox delivery. Provider costs differ: SendGrid says sandbox calls consume no credits, while Mailgun says test-mode messages are charged. Use the provider response to catch supported request errors before a real send attempt.
Use a dedicated, team-owned test mailbox for any check that needs to confirm rendering, arrival, or timing — and run it on a schedule or before a release, not on every commit, since it's a real send against a real inbox.
Keep a third set of tests that never touch the provider at all, asserting on the bot's send decision against fixtures. If you only have budget for one kind of test, write this one first: it's the cheapest, and it's the layer most likely to expose a bot that would have emailed the wrong person.
- Sandbox/test mode: CI where appropriate, checks the provider response, zero delivered messages; check provider charges
- Dedicated test mailbox: scheduled or pre-release, checks rendering and delivery
- Decision-logic fixtures: every commit, checks recipient and trigger logic with no network call
Sources: Sandbox Mode, Sending Messages in Test Mode.
Primary sources
Sources checked 2026-10-13. Standards and product documentation can change; follow the linked version when implementing.
- Sandbox Mode — Twilio SendGrid
- Sending Messages in Test Mode — Mailgun
BotBento is in development. Suggest a correction.