== How we make Exim discard bounces of spam Making Exim discard things in general is simple: you create an Exim router using the _redirect_ driver that blackholes messages, and guard it with a suitable set of conditions. I decided to be safe, so we only discard locally generated bounces of spam that are going to an outside domain. (You can detect locally generated bounces with the condition '((and {{!eq{$interface_port}{25}} {!def:return_path}}))'. The easy way to discard messages is to use '_data = :blackhole:_' in the router; we actually use an Exim filter, because it lets us do somewhat better logging and makes for an easier way to check the 'is a bounce of spam' condition.) The tricky bit is detecting that this bounce is a bounce of spam, and doing so reliably. Exim routers and filters only have convenient access to headers, and when you're dealing with a bounce this means the headers of the bounce itself, not the headers of the message that bounced. You can dig into the body a bit, but that's unstructured text with all of the problems that that implies. However, Exim lets you customize the generated bounce message via the ((bounce_message_file)) main configuration setting; in particular, you can add headers to it, and when the bounce message is generated you *do* have access to the original message's headers. Our [[spam filter ../spam/CSLabSpamFiltering]] tags the _Subject:_ header, so we have a custom bounce message that copies the original message's _Subject:_ into the bounce as _X-Original-Subject:_. Our bounce-discarding router then recognizes bounces of spam by looking for this header and then checking to see if it starts with the magic tags. (We don't have to worry about users accidentally putting this header in their messages and having them get discarded, because we only trigger for locally-generated messages with the null envelope sender. Technically a user that tried hard enough could generate such a message, but then they could just send it to _/dev/null_ directly.)