Skip to content

Fighting SPAM Bounces with Exim (Part II)

In the previous article I described how you can reduce the number of bounce mails generated by your mail server. In this article, I will describe a method to automatically distinguish between legitimate and unsolicited bounce mails, thus reducing the number of bounce mails you receive.

Bounce mails should always be sent to the envelope sender (aka "return path") and the bounce mail itself should use an empty envelope sender (some misconfgured systems however use "postmaster@...").

As the user usually does not see the envelope sender, we can set it to anything different from the true sender's address. In fact we can append some kind of signature to the local part of the address, which proves that the mail has really been sent by our mail server. The spammer does not now this signature (which contains a timestamp), unless he has received a mail from us very recently, and therefore will use the normal address (which might have been collected from some webpage or whois information).

Then our mail server can just reject any bounce mails to an address with an invalid signature, because it is probably not a reaction to a mail from our server. This mechanism is called Bounce Address Tag Validation (BATV) and supported by newer Exim versions.

In the first section of our Exim configuration, we define a macro containing the secret signing key and the list of addresses, we want to enable BATV for:

PRVS_SECRET=VerySecretKeyThatYouHaveToChange
addresslist prvs_senders = an-address@example.com : another-address@example.com

If you want to enable BATV for all addresses, you could skip this step and enable BATV for a list of whole domains. However, usually only a few addresses are affected by spam bounces and enabling BATV only for them reduces the risk of breaking something.

Then you have to extend the acl_smtp_rcpt ACL with the following rules:

  deny    message     = This address does not send an unsigned return path
          senders     = : postmaster@*
          recipients  = +prvs_senders

  deny    message     = Invalid return path signature
          senders     = : postmaster@*
          condition   = ${prvscheck {$local_part@$domain}{PRVS_SECRET}{1}}
         !condition   = $prvscheck_result

The first rule will deny bounce mails (actually any mails with an empty envelope sender or postmaster@ in the envelope sender) which are targeted at a BATV enabled address and do not have a signature. The second rule checks any bounce mails that have a signature for the correctness of this signature.

In the next step we have to add a router that rewrites a BATV address to the original address:

prvs_redirect:
  driver = redirect
  data = ${prvscheck {$local_part@$domain}{PRVS_SECRET}}

This router should be placed following any remote but preceding any local routers.

Finally, we have to add the signing configuration to the SMTP transport:

remote_smtp:
  driver = smtp
  return_path = ${if match_address{$return_path}{+prvs_senders} \
{${prvs {$return_path}{PRVS_SECRET}}}{$return_path}}

This will cause the sender address to be signed, if it is listed in prvs_senders.

Since enabling this, I receive virtually no spam bounces any longer.

Fighting SPAM Bounces with Exim (Part I)

In a perfect world there would be no spam and no bounce mails generated by spam. However, in the real world there is spam and there are badly configured mail servers, which generate bounce mails for invalid addresses.

Fighting spam is a complex task and there are many different approaches but no real solution. However, there are two simple and effective measures to fight bounce mails generated by spam:

First, you should take care to adjust your Exim configuration in order to minimize the number of bounce mails generated by your mail server. This will not reduce the amount of unsolicited bounce mails you receive, but it will dramatically reduce the number of bounce mails your mail server sends to the poor guy, whose address is abused by spammers for the "return path" (aka "envelope sender").

The solution is very simple: Just tell your mailserver to verify a recipient's address before accepting mail for it. The mailserver usually does this for local mail addresses, but you have to tell the server to do it for remote addresses, too. You do this by adding the line

require verify = recipient/callout=10s,defer_ok

to your Exim configuration. This way the mailserver will connect to the destination mail server and check the address before accepting a mail. If the destination mail server does not accept the local part, Exim will decide that the address is invalid and reject the mail without generating a bounce mail. If the destination mail server is down, Exim will still accept any local part. In fact this will cause bounce mails for invalid addresses again, however this will happen much more infrequently, because the destination mail server is up most of the time.

Now this article is longer than I expected, so I will describe the second measure (which will dramatically reduce the number of bounce mails you receive) in a second article.