Virtual Domain Aware Mail Filtering
Many people who have personal servers handle email for a number of domains, and struggle to deal with the ever-increasing volume of spam, junk, and virus-laden email.
There are solutions for dealing with this problem, ranging from hosted services, to software you must run yourself.
This page documents a consistent and extensible solution built around open source software, which allows you to handle mail filtering for multiple domains without complex configuration.
The software presented here consists of a co-ordinated collection of plugins that can be used with the qpsmtpd SMTP server to offer a system that will filter email for a number of domains, and allow you to specify different filtering for different domains.
It is helpful if you're familiar with qpsmtpd so that you can install it and and understand how it works, but that isn't entirely necesary.
Once installed this collection of plugins will give you:
To get started you'll need to install qpsmtpd and configure it to use the ms-lite plugins.
Actually installing qpsmtpd, and configuring it to listen upon your public IP on port 25 is outside the scope of our documentation.
Once you've configured qpsmtpd to load the plugins there are three things you must do to get up and running:
- Create the quarantine/archive directory.
- Specify users & the filtering options for your domains.
- Configuring The Rejection Quarantine
Configuring the quarantine directory is as simple making a directory and then configuring the permissions on it:
root@host:~# mkdir /spam
root@host:~# chown qpsmtpd.qpsmtpd /spam
root@host:~# chmod 750 /spam
This will give you a local directory to which the qpsmtpd user can both read and write.
- Configuring The Domains
Configuring the domains is a simple process of creating files and directories, but we'll come back to that later.
Domains & Domain User Setup
To configure which domains and users will have their mail accepted we need to create a couple of directories for each domain beneath /srv. (This prefix /srv is fixed, just as the quarantine directory must be located at /spam.)
For each domain you specify users by creating entries in the directories:
To demonstrate how this works we'll show how you'd configure the two domains "example.com" and "invalid.org". We'll configure these domains to work like this:
This will accept mail for only a few local users.
This domain will have wildcard handling so any account will accept mail, with the one exception that mail addressed to email@example.com will be rejected.
To get started we configure example.com:
mkdir -p /srv/example.com/users/valid/
Here we've configured the domain example.com to accept mail addressed to firstname.lastname@example.org, email@example.com, firstname.lastname@example.org, and email@example.com - mail to all other accounts will be rejected (and stored in the quarantine)
For invalid.org the setup is almost the same. We use the same "/users/valid" path, but instead of creating accounts we create a file called *:
# wildcard users - except the user "spam" is invalid
mkdir -p /srv/invalid.org/users/valid/
mkdir -p /srv/invalid.org/users/invalid
As you can see we've configured this domain to accept mail to all users except the user firstname.lastname@example.org.
Now that you've configured the users and the domain names mail will start to be accepted be delivered as expected - however we've not yet configured any filtering.
The configuration of filters follows the same pattern as the user setup, it merely involves the creation of a couple more files and directories.
Configuring The Filtering
We've already seen that to get a new domain going you need to create entries in the special directories:
Configuring the various filters is achieved in the same fashion. You must merely touch files in the directory /srv/$domain/checks.
There are several filters included in the distributed list and we can enable all of them for our two example domains by running:
mkdir -p /srv/example.com/checks
mkdir -p /srv/invalid.org/checks
However you might prefer to enable different checks on a per-domain basis. That is also possible - rather than creating /checks/all create one file for each test you wish to be enabled on this domain.
For example to only enable the helo and date checks for the domain you'd run this:
rm -rf /srv/invalid.org/checks
mkdir -p /srv/invalid.org/checks
How do you know what filenames to use? That is simple. The filename you create matches the name of the plugin in the source - this is also documented in the example plugins file.
Whitelisting & Blacklisting
Any anti-spam system will make mistakes from time to time, and the simplest way of avoiding repeats is to make use of whitelisting.
We allow messages to be whitelisted based upon either the email address that sent the message, the account it is addressed to, or the host that delivered the mail to us.
Like the prior setup this is again configured by creating files in a particular set of directories:
- Whitelisting Senders
Create files in /srv/domain/whitelisted/senders/. For example if you wish to always accept email from the user email@example.com you'd run this:
mkdir -p /srv/example.com/whitelisted/senders
- Whitelisting Recipients
Create the files in the directory /srv/$domain/whitelisted/recipients/. Note the domain name is implied by the directory name, so you don't need to repeat it.
For example if you run a helpdesk and people forward spam complaints to the address firstname.lastname@example.org you'd always want to accept them even if they looked like spam so you'd run this:
mkdir -p /srv/example.com/whitelisted/recipients
- Whitelisting Hosts
Finally to whitelist the hosts that are sending you email you need to create files beneath /srv/domain/whitelisted/ips/. As an example to always accept mail addressed examle.com from the IP address 220.127.116.11 you'd run:
mkdir -p /srv/example.com/whitelisted/ips
These whitelisting settings are applied to all mails, and you don't need to restart the service for changes to take effect.
Blacklisting is achieved in a virtually identical fashion, the only change is that you use /srv/$domian/blacklisted as the prefix instead. So you might blacklist a hostname, an IP address, or even a sending address or domain via commands like:
# Blacklist the IP address 18.104.22.168 from sending you mail.
# Block all mail from linkedin.com
# Blacklist mail from email@example.com
For each of the blacklist and whitelist options you can choose to apply these overrides or blacklists on a per-domain basis, as we have done above, or globally via the magic prefix of /srv/_global_/.
For example if you never wished to receive mail from AOL users you could run this:
mkdir -p /srv/_global_/blacklisted/domains/