Tools · runs in your browser
Dev mail fence
A staging server that mails real customers is the classic email accident. Fill in who may get real mail on staging and copy one send function that sends nothing unless an environment is told to.
1. The send function
Put it in one file and make every email in the app go through it. It reads three settings from the environment and has no other dependencies.
2. The settings for each environment
3. Check it before you trust it
| MAIL_MODE | Result | What happens to mail for |
|---|
The link in your address bar keeps these settings, so you can paste it into a pull request. Nothing you type here is sent anywhere.
Why it's built this way
- Doing nothing is the safe state. A new laptop, a CI runner or a preview deployment has no
MAIL_MODE, so it prints the email and sends nothing. A value it doesn't know, such asprodorproduction, also captures. Only the exact wordsallowlistandliveopen the road. - Staging redirects, it doesn't swallow. Mail for anyone outside the allowlist goes to one team inbox with the original recipient in the subject and in the plus tag, so a tester still sees that the email went out and can filter by who it was for. The catch inbox has to accept plus addresses; Gmail, Google Workspace, Outlook.com, Microsoft 365, Fastmail and iCloud do.
- The allowlist matches whole domains, not text.
yourcompany.comletsjo@yourcompany.comthrough and stopsjo@notyourcompany.comandjo@yourcompany.com.example.net. A full address on the list matches only itself. - A refused send is an error, not a shrug. If the API answers anything but 2xx, the function raises, so a wrong key on production shows up in your logs on the first email.
- It only works if it's the only door. Search the codebase for other places that talk to a mail server or a mail API: the password reset written two years ago, the cron job a contractor added.
The whole approach, with a local catch-all inbox for SMTP and test addresses that can't belong to anyone: Test emails that never reach a real person.
Tested by running each function against a stand-in server with the mode unset, misspelt, allowlist and live. Use a separate key for staging and for production; development needs none.
One HTTPS call behind the fence
email59 is an email router with a small API for sign-in codes, alerts and notices. No domain setup, no subscriptions.