]> Weighting e-mail spam based on country of origin with SpamAssassin 🌐:aligrant.com

Weighting e-mail spam based on country of origin with SpamAssassin

Alastair Grant | Friday 21 August 2020

E-mail is a global phenomenon, whether the person is in the same town or on the other side of the world, mail is delivered almost instantaneously.  A fantastic achievement, but not always entirely relevant, I have little business to conduct with organisations in Russia or Brazil, yet I still receive spam from these countries.  There are some services that I can block off entirely to countries, but e-mail is something that I potentially need to receive from senders anywhere in the world; not only do businesses operate globally, the mail servers email is routed through could be anywhere.  But, it's not frequent.

SpamAssassin has a bundled plugin called RelayCountry, which will identify the country emails have gone through, based on a lookup of the IP address.  This allows you to add some weighting to spam rules depending on the country (or junk it outright).

But as with anything related to SpamAssassin, Amavis and Perl, it's not always very easy to configure.  And to add another spanner in the works, MaxMind the life-long provider of free geolocation services have changed the format of the database files a few years ago and now require registration (still free) and license keys to access the data, making updating even more complicated.  Fortunately if you do not need any of the new functionality, then you can carry on using the legacy database format from other locations.

Configuring Geo::IP

First of, we need the Perl module Geo::IP installed.  What is easy to miss with this though, is you'll need to have the GeoIP C API installed too; the module will install without it, but won't work with SpamAssassin.  As the perl module will be built, you'll also need the GeoIP development files.  Both of these components should be available from your distribution and if not you'll have to compile them yourself.  As always, I'll use openSUSE as an example:

zypper install libGeoIP1
zypper install libGeoIP-devel

This will install the required C libraries.  Unfortunately for me, Geo::IP isn't one of the modules that is bundled with my distribution, so I'll need to use CPAN to build the modules manually.

$ sudo cpan
cpan[1]> force install Geo::IP

The force will rebuild the module if it's already installed.  Running as root will allow it to install site wide instead of just for the current user.  Keep an eye for an error about the C API not being installed, if you get that, then it's not going to work and you'll need to revisit the first step.

Geo::IP databases

The GeoIP databases will need to be downloaded and placed in the relevant location.  This is another slightly confusing thing as some distributions put them in different places and some applications are hard coded to look in others.

I put the GeoIP.dat and GeoIPv6.dat files into /var/lib/GeoIP, but also created a symlink to this directory from /usr/local/share/GeoIP, which seems to have done the job.

Configuring SpamAssassin

Now the prerequisites are installed, we can enable the module for SpamAssassin, the module needs to be loaded by editing the relevant *.pre configuration file.  This can be found somewhere like /etc/mail/spamassassin/.  How do you know which file?  Well how indeed.  grep RelayCountry * will list all references, but it's safe to just use init.pre:

loadplugin Mail::SpamAssassin::Plugin::RelayCountry

The plugin is now there, but won't be doing a lot, you can now configure SpamAssassin to score certain countries as you like.  This can be positive or negative scores, depending which way you want to nudge things.  This can be configured either site wide, or in your local user's configuration.

header          RELAYCOUNTRY_BAD X-Relay-Countries =~ /CN/
describe        RELAYCOUNTRY_BAD Relayed through China at some point
score           RELAYCOUNTRY_BAD 3.0

header          RELAYCOUNTRY_GOOD X-Relay-Countries =~ /^(FI|SE)/
describe        RELAYCOUNTRY_GOOD Last untrusted relay is Finland or Sweden :-)
score           RELAYCOUNTRY_GOOD -0.2

The matching is a regular expression match, so you can put in more complicated matches of two-letter country codes if you can think of any.  Be sure not to put too high scoring as scores are additive, and you might land up sending legitimate email to junk.

And if you want to see what is happening in your mail headers, then you can add this line:

add_header all Relay-Country _RELAYCOUNTRY_


You are quite possibly using amavis-new to handle mail filtering, instead of SpamAssassin directly.  Amavis is a rotten program to configure, fortunately there isn't a lot you need to do.  If you want to see the X-Spam-Relay-Country header in your mail and you're using amavis, then you'll need to add this to your /etc/amavisd.conf

$allowed_added_header_fields{lc('X-Spam-Relay-Country')} = 1;

This will stop amavis from deleting the header after SpamAssassin adds it (not sure why it does this, and I'm not sure if there is a global way of allowing all injected headers).

Your mail should now be weighted depending on the countries it relays through and you can see all hops in the headers.

Example regular expressions

  • Origin from the UK (and ignores private hosts): /GB(\s\*\*)*$/
  • Passes through Brazil: /BR/
  • Doesn't pass through Canada: /^((?!CA).)*$/

You can use an online regular expression tester to try other ones out.

Breaking from the voyeuristic norms of the Internet, any comments can be made in private by contacting me.