Making your SMTP rejection messages be useful for you

April 5, 2017

Our external mail gateway will reject (some) incoming messages during the SMTP conversation if our anti-spam system thinks they have too high a spam score. Until today, they were rejected with a deliberately bland and uninformative SMTP error message:

550 Rejected: this message looks too much like spam

When I designed this message, I wrote a comment about it saying 'rejections for spam deliberately give the sender an uninformative message because I don't feel like giving spammers clues'. Then today we got called in to help troubleshoot an issue where a (valid) email message from outside had bounced, and all we had to go on was this message.

Well, you know what: spammers probably aren't reading our SMTP rejection messages anyways, but we certainly do every so often. If we're reading the message this version is exceedingly unhelpful; in fact it's so generic that it's not immediately clear if it's from our system or some other system. So now our SMTP time rejection message for spam says this:

550 Rejected: CSLab PMX spam score too high (milter id <something>)

This new form does several things. First, it clearly identifies to us that the message comes from our external mail gateway. Then, between the 'milter id' and the 'PMX spam score' wording, it tells us which SMTP-time rejection is being triggered here; it's our milter-based system. Finally, the <something> is the Exim (log) ID that was assigned to the proto-message as it was being received. Using this ID we can efficiently retrieve all of the other information about the message from our logs, including the specifics of its spam score (such as they are, given that Sophos PureMessage's spam scoring is basically a black box).

Having done this exercise for one SMTP rejection message, I'm sort of tempted to do it for others. If I start from the premise that someday a user will turn up saying 'someone trying to mail me got this message', what do I want to see in the message so we can explain the situation to people?

(The good news is that I took a quick look and almost all of our other SMTP rejection messages seem to include the crucial information. For example, our 'rejected because the sending IP is in Spamhaus' SMTP rejection message actually includes the IP address, so we don't have to try to correlate logs with whatever vague information we have about the rough time the message was sent to the particular user in order to find it.)

By the way, one consideration here is that you don't necessarily want these messages to be too long, because some SMTP senders will truncate your rejection message when they report it to users (or at least they used to). I believe I've seen ones that only report the first line, for example. This is why our current rejection message is going to be relatively cryptic to anyone but us; I cautiously squeezed it down to something that I felt had a relatively high chance of making it back to us intact.

I don't get many bounce messages these days, so it's possible that modern mail systems no longer suffer from this issue. Certainly mail providers like Google and Yahoo generate quite long and verbose multi-line SMTP rejections and temporary failures. Perhaps I should add a second line with a clear, normal person focused explanation for anyone who trips over this as a legitimate false positive.

Written on 05 April 2017.
« Why the modern chown command uses a colon to separate the user and group
Spammers probably aren't paying any particular attention to you »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Apr 5 23:41:56 2017
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.