When two safety checks hide each other
31 July 2026 · 5 min read
We were adding support for customers bringing their own domain. Mail for a new domain was refused, so we changed the mail server’s configuration to allow it. Still refused. Reloaded. Still refused. Restarted the whole server. Still refused, with the configuration demonstrably correct.
The message was ours
A single grep for the error string found it in our own code. The mail server was handing every recipient to our application, and our application was refusing anything outside a hard-coded list. We had spent three rounds reconfiguring somebody else’s software to fix a message we were printing ourselves.
Then the opposite mistake
Having concluded the mail server was irrelevant, we removed the configuration work. Mail for a real address on that domain then failed with a different message, from the mail server, because it gates acceptances even though our code gates rejections. Both gates existed. Testing only an unknown address never reached the second one.
What we took from it
- Grep your own error strings before theorising about someone else’s software.
- Two gates can mask each other: test the accept path and the reject path separately.
- A test that only exercises failure will not tell you success works.
More on for developers
Testing signup emails in CI without a real mailbox
Sleep-and-hope is why your email tests are flaky. Here is the shape that is not.
Webhook signatures, done properly
A shared secret in a header is not a signature. Here is what to send, what to check, and the two mistakes almost everyone makes on the receiving end.
Rate limiting on the wrong axis is worse than none
Per-IP limits punish shared offices and mobile networks while doing nothing to an attacker who rotates addresses for pennies.