In this post, I describe how to set up spam filtering rules based on the country that an email was sent from, using SpamAssassin. These notes are based on Debian Bookworm, but the principles are very similar for other versions of Debian and Ubuntu. If you run a mail server that primarily only receives mail from a few countries, this guide should be very helpful to you in the fight against spam.
SpamAssassin is very powerful, but its documentation is a little sparse in places. Nothing in this post is new, but it explains in much more detail than the official SpamAssassin documentation both what to do, and why to do it.
Before starting, I want to mention the rationale for what we’re doing. If you just want to get on with setting up filtering, feel free to skip this section!
Most smaller mail servers don’t receive genuine mail from more than a few countries. For example, if you’re running a mail server for an organisation in Europe, you probably only receive mail from your own country, plus the USA and a few other European countries (knowingly or not – chances are that many of your contacts are using a major hosted email provider, who may not have datacentres in your country, but almost certainly have them in the USA and/or Europe). This means that if you receive mail from another country, there’s a much higher chance that it is spam. The instructions below allow SpamAssassin to check which countries an email passed through before reaching you, and increase the spam score. I’ve deliberately not set anything to reject the email completely, it’s just more likely to be filtered.
SpamAssassin has some official documentation on how to set this up, but it’s very confusing. The biggest problem is that they list four different possible data sources for the IP address country lookup, but none of them work out of the box with Debian. I ended up using
IP::Country::DB_File because it’s straightforward to set up, and importantly also straightforward to keep up to date, thanks to Henrik Krohns.
When I first set up country-based spam filtering several years ago, I used
IP::Country::Fast. However, it very rarely receives updates these days.
GeoIP2::Reader::Database appears to be the best data source from a technical perspective, but setting up automated data updates doesn’t seem to be possible without a paid subscription.
Geo::IP seems relatively straightforward but I wasn’t able to get it to work in my testing. There were no errors, but it just didn’t detect the country.
In order for SpamAssassin to translate an IP address into a country, we need the PERL CPAN module
IP::Country::DB_File. Unfortunately this module isn’t available as a prebuilt package for Debian, so we’re going to build it ourselves. First, install some required and helpful packages:
apt install libmath-int64-perl dh-make-perl libsys-cpu-perl libdpkg-parse-perl
Next, create a .deb package of the module and install it:
dh-make-perl --build --cpan IP::Country::DB_File
dpkg -i libip-country-db-file-perl_3.03-1_all.deb
Now, create a cron job to automatically update the IP/country database every week and run it once manually to initialise the database.
Put these contents in the file:
#!/bin/sh # @see https://spamassassin.apache.org/full/3.4.x/doc/Mail_SpamAssassin_Plugin_RelayCountry.txt # @see https://cwiki.apache.org/confluence/display/SPAMASSASSIN/RelayCountryPlugin # @see https://mailfud.org/ip-country-dbfile/ DIR=/usr/local/share/ip-country-dbfile/ if [ ! -d "$DIR" ] then mkdir -p "$DIR" fi curl --silent --location 'https://mailfud.org/ip-country-dbfile/ipcc.db.gz' > "$DIR"ipcc.db.gz gunzip --force "$DIR"ipcc.db.gz
Make the cron job executable and run it:
chmod +x /etc/cron.weekly/ip-country-dbfile
Uncomment the following line in
Add the plugin configuration to the bottom of
# Blocklist based on countries message has been relayed through # # Countries included are Albania, Algeria, Argentina, Armenia, Belarus, # Bosnia and Herzegovina, Brazil, Brunei, Chile, China, Colombia, Croatia, # Czechia, Dominican Republic, Egypt, India, Indonesia, Iraq, Japan, Jordan, # Kazakhstan, Korea, Malaysia, Mexico, Mongolia, Pakistan, Peru, Philippines, # Poland, Qatar, Romania, Russia, Saudi Arabia, Serbia, Sri Lanka, Taiwan, # Thailand, Turkey, Ukraine, Venezuela, Vietnam, Unknown EU # Older versions of Debian and SpamAssassin used these configuration options: #country_db_type DB_File #country_db_path /usr/local/share/ip-country-dbfile/ipcc.db # Since Debian Bookworm and SpamAssassin 4.0.0 the options have been renamed: geodb_module DB_File geodb_options country:/usr/local/share/ip-country-dbfile/ipcc.db #add_header all Relay-Country _RELAYCOUNTRY_ header RELAYCOUNTRY_BAD X-Relay-Countries =~ /(AL|DZ|AR|AM|BY|BA|BR|BN|CL|CN|CO|HR|CZ|DO|EG|IN|ID|IQ|JP|JO|KZ|KR|MY|MX|MN|PK|PE|PH|PL|QA|RO|RU|SA|RS|LK|TW|TH|TR|UA|VE|VN|EU)/ describe RELAYCOUNTRY_BAD Sent from an IP address in a country with a high risk of spam score RELAYCOUNTRY_BAD 2.0
You should adapt the list of countries to your needs. This list works well in our experience with UK-based mail servers. If you want extra debugging information, uncomment the line
add_header all Relay-Country _RELAYCOUNTRY_. This will add a header to every email of the form
X-Spam-Relay-Country: XX YY ZZ, where XX, YY and ZZ are the country codes of the countries the mail passed through before reaching your server.
Test and reload SpamAssassin
Check that SpamAssassin thinks your configuration is valid with
If there were no errors, you can restart SpamAssassin with
systemctl restart spamassassin.service
If you’re still struggling with spam on your servers and would like professional assistance, please contact us. With over a decade of experience managing mail servers, including inbound spam filtering and outbound deliverability, we can definitely help you!
Thanks for taking the time to document this. Worked flawlessly on Debian 10!
No problem, glad to hear it!
We also setup on our mailservers with Debian 11. It also works fine on Debian 11 servers.
SpamAssassin 4.0.0 changed to use a different internal module to handle IP address country lookups. This is mentioned in the release notes at https://github.com/apache/spamassassin/blob/trunk/UPGRADE but the configuration changes required are not specified anywhere that I could find - the release notes mention the new names of the required options, but not their expected values or syntax. I ended up having to look at the source code in order to work out how to continue using DBFile. I've updated the article to include the new syntax. Hopefully this is useful! Without it, SpamAssassin will fail to upgrade cleanly when upgrading Debian Bullseye to Bookworm.