Sandbox and test modes for an email API: what to simulate
A good email API sandbox does more than return 200. See which outcomes to simulate: bounces, complaints, delays, rate limits and webhooks, and how to test each.

On this page(6 sections)
- What a sandbox is for
- The outcomes worth simulating
- Accepted and delivered
- Hard bounce
- Soft bounce and deferral
- Spam complaint
- Unsubscribe or opt-out
- Rejected request
- Authentication and permission errors
- Rate limits
- Timeouts and server errors
- Delayed webhooks and duplicates
- How to test when the sandbox is thin
- Keep sandbox and production apart
- A short test checklist
- What to remember
Most email bugs do not show up on the happy path. The welcome email sends, the API returns success, and the test passes. The trouble starts weeks later, when an address bounces, a customer marks a message as spam, or your provider answers with a rate-limit error at the worst moment.
A sandbox or test mode is where you can meet those cases safely. This guide lists what a useful sandbox should let you simulate, how to test each case, and what to do when your provider's sandbox is thin.
What a sandbox is for
A sandbox is a mode of an email API that accepts your requests, behaves like the real service, but does not deliver to real inboxes. Providers call it different things: test mode, sandbox key, dry run, or a set of special addresses. The names vary; the purpose does not.
It should answer three questions:
- Does my request format work? Authentication, required fields, attachments, headers.
- Does my code handle every response the API can give?
- Does my system react correctly to events that arrive later?
If a sandbox only answers the first question, it is a syntax checker. The second and third are where production incidents come from.
The outcomes worth simulating
Here is a practical list. For each one, check whether your provider can produce it on demand, and if not, how you will fake it.
Accepted and delivered
The baseline. Confirm that a successful send gives you an identifier you store, and that a delivered event, if your provider sends one, updates the right record.
Hard bounce
The address does not exist. Your system should stop sending to it, mark it in your own data, and not retry. A common bug is retrying a permanent failure forever because the code treats every error as temporary.
Soft bounce and deferral
The mailbox is full, or the receiving server is busy. The message may be retried by the provider for hours. Test that your app does not show "failed" to a user while delivery is still in progress, and that it shows something honest if the message finally gives up.
Spam complaint
A recipient pressed the spam button. Your system should suppress that address from further mail, at least for the kind of message that triggered it. Many teams build the suppression list and never test it.
Unsubscribe or opt-out
If your messages carry an unsubscribe link or header, the action should reach your data and be honored on the next send. Test it end to end, including for transactional mail where the policy may differ from marketing mail.
Rejected request
The API refuses before sending: invalid address, missing field, message too large, attachment type not allowed. Check that your app shows a useful message and does not silently drop the email.
Authentication and permission errors
A revoked or wrong key should fail loudly and alert someone. Try a bad key on purpose and see what your monitoring does.
Rate limits
The API answers with a "too many requests" status. Your sender should slow down, respect the retry hint if one is given, and keep the queue intact. See how to handle 429 errors for the pattern.
Timeouts and server errors
The request hangs or returns a 5xx. The hard question is whether the email was sent or not. Use an idempotency key if the API supports one, or store a send attempt record before you call the API so you can reconcile later.
Delayed webhooks and duplicates
Events arrive late, out of order, or twice. Your handler should be safe to run more than once for the same event and should not assume that "delivered" arrives before "bounced".
How to test when the sandbox is thin
Some providers offer a handful of magic addresses; others offer nothing beyond a test key that returns success. You can still cover most of the list.
Put a fake provider behind an interface. Write your sending code against a small interface, with one implementation for the real API and one for tests. The fake can return any status you want: a 429, a 500, a timeout, a validation error. This covers the second question above without any network.
Replay webhook payloads. Save real event payloads from the provider's documentation or your logs, then post them to your own webhook endpoint in tests, in the wrong order and twice. This covers the third question.
Use a local mail catcher for the message itself. For checking how the message looks and which headers it carries, a local SMTP catcher is enough. See local email testing with a fake SMTP server.
Keep one real end-to-end check. Once in a while, send a real message to a mailbox you control and read it. Sandboxes do not tell you about spam folders, rendering in real clients, or DNS problems. Our guide to inbox placement testing covers that side.
Keep sandbox and production apart
Mixing the two is a quiet source of harm. Some rules that prevent it:
- Separate keys, clearly named. A test key and a live key should look different in your configuration, and the live key should exist only in the production environment. See email API key security for storage advice.
- Never send test data to real customers. If you test with a copy of production data, route every send to a safe address or a catcher. A staging system that emails real people is a common and embarrassing mistake.
- Mark test traffic. Add a header or tag so you can filter test messages out of your logs and statistics.
- Check the environment at startup. If the app boots with a live key in a non-production environment, refuse to start, or at least warn loudly.
A short test checklist
Before you ship an email feature, run through this list:
- A normal send returns an id, and the id is stored.
- A hard bounce marks the address as unusable and stops retries.
- A spam complaint suppresses the address.
- A 429 slows the sender down without losing messages.
- A 5xx or timeout does not cause a duplicate send.
- A duplicate webhook does nothing the second time.
- An invalid request shows the user a clear message.
- A wrong key raises an alert.
- Test mode cannot reach real customers.
You will not catch everything, but each item you tick removes a class of surprise from production.
What to remember
A sandbox earns its keep when it lets you fail on purpose. Ask for the bad outcomes first: bounces, complaints, limits and late events. If your provider cannot produce them, build a small fake that can, and keep one real end-to-end check for the things no sandbox can show you.
If you are choosing a provider, ask about test behavior early. The questions to ask when choosing a transactional email API are a good starting list, and "how do I simulate a bounce?" belongs on it.
Start with Koltrix
Your domain, one inbox, and an API that sends.
A team inbox where AI sorts and drafts (nothing is sent without your click), plus the transactional API and SMTP relay your product sends with. 7 days free, no card.


