Sign In
Cold Outreach

How to Pick an Email Spam Filtering Service

Effective Email Spam Filtering: A Deep Dive into Postfix Configuration with SpamAssassin and Dovecot

Email spam remains a persistent threat, overwhelming inboxes and posing security risks. This article delves into the practical aspects of building a robust email spam filtering service using Postfix, SpamAssassin, and Dovecot. We’ll focus on configuring SpamAssassin to integrate seamlessly with Postfix, enhancing its filtering capabilities, and then explore how Dovecot’s Sieve filtering can further refine the spam handling process. This guide provides actionable examples and configuration snippets to empower you to build a highly effective email spam filtering solution.

Table of Contents:

Postfix and SpamAssassin Integration: A Foundation for Filtering

Integrating Postfix and SpamAssassin is crucial for identifying and filtering spam emails before they reach users’ inboxes. Postfix acts as the mail transfer agent (MTA), receiving emails and routing them to the appropriate destination. SpamAssassin, a powerful open-source spam filter, analyzes email content and assigns a spam score. This section will guide you through the process of configuring Postfix to pass emails to SpamAssassin for analysis.

Configuring Postfix’s `master.cf` for SpamAssassin Integration

The `master.cf` file controls Postfix’s daemon processes. We’ll add entries to delegate email processing to SpamAssassin. Open `/etc/postfix/master.cf` with your favorite text editor.

# /etc/postfix/master.cf

spamassassin unix  -       n       n       -       -       pipe
  user=debian-spamd argv=/usr/bin/spamc -f -e
   /usr/sbin/sendmail -oi -f ${sender} ${recipient}

# If using Postfix version >= 3.4, enable SpamAssassin socket operation:
# spamassassin unix  -       n       n       -       -       socket
#  user=debian-spamd argv=/usr/bin/spamc -f -e
#   /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Explanation:

  • `spamassassin unix – n n – – pipe`: Defines a new service called `spamassassin`.
  • `user=debian-spamd`: Specifies the user that the `spamassassin` service will run as. This is typically the user associated with the SpamAssassin daemon (spamd).
  • `argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}`: Defines the command to execute when the service is called.
    • `/usr/bin/spamc`: The SpamAssassin client program.
    • `-f`: Passes the message through.
    • `-e`: Reports exit code of the program.
    • `/usr/sbin/sendmail -oi -f ${sender} ${recipient}`: Hands the message back to Postfix for delivery after processing by SpamAssassin. `-oi` ignores dots alone in lines, and `-f ${sender}` sets the sender address.

Important Note: Replace `debian-spamd` with the actual user your `spamd` process runs as if it’s different. You can usually check this with `ps aux | grep spamd`. Also, if you’re running a more recent Postfix version (3.4 or later), you should enable the socket method of operation (commenting out the pipe version and uncommenting the socket version). Using the socket method is generally more efficient.

Modifying `main.cf` to Utilize SpamAssassin

Next, we need to modify Postfix’s main configuration file (`/etc/postfix/main.cf`) to direct emails to the `spamassassin` service we defined in `master.cf`. Add or modify the following lines:

# /etc/postfix/main.cf

receive_header_checks = regexp:/etc/postfix/header_checks
smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination,
    check_client_access hash:/etc/postfix/client_checks,
    check_helo_access regexp:/etc/postfix/helo_checks,
    check_sender_access regexp:/etc/postfix/sender_checks,
    check_recipient_access regexp:/etc/postfix/recipient_checks,
    reject_rbl_client zen.spamhaus.org,
    reject_rbl_client bl.spamcop.net,
    reject_rbl_client dnsbl.sorbs.net,
    check_policy_service unix:private/spamassassin,
    permit

content_filter = spamassassin:[127.0.0.1]:10025
receive_override_options = no_address_mappings

Explanation:

  • `receive_header_checks = regexp:/etc/postfix/header_checks`: Enables header checks based on regular expressions defined in `/etc/postfix/header_checks`. This allows you to filter based on specific header content.
  • `smtpd_recipient_restrictions`: A series of checks performed when an email is received. The order is critical.
  • `permit_mynetworks`: Allows connections from your internal network without further checks.
  • `permit_sasl_authenticated`: Allows connections from authenticated users.
  • `reject_unauth_destination`: Rejects emails destined for domains that the server isn’t configured to relay for.
  • `check_client_access hash:/etc/postfix/client_checks`: Checks the client’s IP address against a hash table in `/etc/postfix/client_checks`.
  • `check_helo_access regexp:/etc/postfix/helo_checks`: Checks the HELO/EHLO string against regular expressions in `/etc/postfix/helo_checks`.
  • `check_sender_access regexp:/etc/postfix/sender_checks`: Checks the sender’s email address against regular expressions in `/etc/postfix/sender_checks`.
  • `check_recipient_access regexp:/etc/postfix/recipient_checks`: Checks the recipient’s email address against regular expressions in `/etc/postfix/recipient_checks`.
  • `reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, reject_rbl_client dnsbl.sorbs.net`: Rejects emails from clients listed on Realtime Blackhole Lists (RBLs) like Spamhaus ZEN, Spamcop, and SORBS.
  • `check_policy_service unix:private/spamassassin`: Specifies that the `spamassassin` service (defined in `master.cf`) should be used as a policy service. This tells Postfix to pass the email to the `spamassassin` service.
  • `content_filter = spamassassin:[127.0.0.1]:10025`: Configures a content filter, which is a service that processes the email content. In this case, it’s set to `spamassassin` running on `127.0.0.1` (localhost) on port `10025`. This connection will be handled by the `spamassassin` service we defined in master.cf. This line essentially redirects the email to SpamAssassin for scanning.
  • `receive_override_options = no_address_mappings`: Disables address mappings during the receiving process. This is important to prevent unintended side effects when SpamAssassin modifies the email headers.

Important Considerations:

  • The order of `smtpd_recipient_restrictions` is crucial. Place stricter rules (like RBL checks) *before* checks that require more resources (like SpamAssassin).
  • Ensure that SpamAssassin (`spamd`) is running. You can check its status with `systemctl status spamassassin`.
  • The `content_filter` setting needs a corresponding entry in `master.cf`.
  • The above `master.cf` assumes that SpamAssassin listens on a Unix socket and not a TCP port. The `content_filter` line assumes that Postfix connects to the spamassassin service on the localhost TCP port 10025, which is usually the default behavior of the service. If using the socket version in `master.cf`, remove the `content_filter` line entirely.

After making these changes, restart Postfix: `sudo systemctl restart postfix`.

Creating Header, Client, HELO, Sender and Recipient Checks (Optional but Recommended)

The `receive_header_checks`, `check_client_access`, `check_helo_access`, `check_sender_access`, and `check_recipient_access` configurations provide a flexible way to block unwanted mail based on different criteria. Here’s a brief overview and examples:

  • `/etc/postfix/header_checks` (regexp): This file contains regular expressions to match specific headers. For example, to reject emails with a “Subject” header containing “Viagra”:
/^Subject:.*Viagra/ REJECT Subject contains unwanted keywords
  • `/etc/postfix/client_checks` (hash): This file contains a list of client IP addresses or networks that should be rejected or accepted. You need to use `postmap` to create the database file.
    Example:
# /etc/postfix/client_checks
192.168.1.10 REJECT
10.0.0.0/24   REJECT
127.0.0.1     OK

#To create database file
sudo postmap /etc/postfix/client_checks
  • `/etc/postfix/helo_checks` (regexp): This file contains regular expressions to match the HELO/EHLO string sent by the client. Spammers often use invalid or generic HELO strings.
    Example:
/^\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]$/  REJECT Invalid HELO
/^localhost/ REJECT Generic HELO string
  • `/etc/postfix/sender_checks` (regexp): This file contains regular expressions to match the sender’s email address.
    Example:
/@spammerdomain\.com$/ REJECT Blacklisted sender domain
/baduser@/             REJECT Blacklisted sender username
  • `/etc/postfix/recipient_checks` (regexp): This file contains regular expressions to match the recipient’s email address. This is less common but can be useful in specific scenarios.
    Example:
/abuse@example\.com$/  OK # Allow mail to abuse address
/postmaster@example\.com$/ OK # Allow mail to postmaster address

Remember to run `sudo postmap /etc/postfix/filename` after modifying any of the hash files (`client_checks`) and `sudo systemctl reload postfix` after modifying any of the files to apply the changes.

Expert Tip: Implementing RBLs and basic access controls significantly reduces spam volume before SpamAssassin even processes the emails, saving valuable server resources.

Senior System Administrator

Advanced SpamAssassin Configuration: Fine-Tuning Your Defenses

While the default SpamAssassin configuration provides basic spam filtering, customizing its settings can dramatically improve its accuracy and effectiveness. This section explores advanced configuration options, including adjusting scoring thresholds, whitelisting/blacklisting addresses, and enabling additional rule sets.

Adjusting Scoring Thresholds

SpamAssassin assigns a score to each email based on its analysis. The higher the score, the more likely the email is to be spam. You can adjust the thresholds at which SpamAssassin takes action. These settings are typically found in `/etc/spamassassin/local.cf`.

# /etc/spamassassin/local.cf

# Required score for considering an email as spam
required_score            5.0

# Score at which to add a report header
report_safe               5.0

# Score at which to rewrite the subject
rewrite_header Subject    *SPAM*

# Score at which to reject the email
# You can set it to a high score to never reject emails based on SpamAssassin score
# but still use its scoring and headers
# If set, you will need to configure a milter or external process to read the score
# and reject the email appropriately.
# rewrite_header Subject    *SPAM*_REJECTED*
# use_auto_whitelist 1
# auto_whitelist_factor 0.5

Explanation:

  • `required_score`: Specifies the minimum score required for an email to be considered spam. The default is typically 5.0. You might want to lower this value (e.g., to 4.0) for more aggressive filtering or raise it if you’re experiencing too many false positives.
  • `report_safe`: Determines the score at which SpamAssassin adds a detailed report to the email header. This report can be helpful for debugging and understanding why an email was flagged as spam.
  • `rewrite_header Subject`: When an email’s score exceeds this threshold, the subject line is modified to include the “*SPAM***” tag. This helps users easily identify potentially unwanted emails.
  • `use_auto_whitelist 1` and `auto_whitelist_factor 0.5`: Enables SpamAssassin’s auto-whitelist feature, which learns from your email patterns and adjusts scores for senders you frequently communicate with. The `auto_whitelist_factor` controls how much weight is given to auto-whitelist entries. Be cautious when enabling this feature, as it can increase the risk of missing spam from previously whitelisted senders.

Restart SpamAssassin after making changes: `sudo systemctl restart spamassassin`.

Whitelisting and Blacklisting

Explicitly whitelisting and blacklisting email addresses or domains allows you to override SpamAssassin’s scoring for specific senders. Use these features carefully to avoid missing legitimate emails or allowing spam to slip through.

# /etc/spamassassin/local.cf

# Whitelist specific email addresses
whitelist_from *@example.com
whitelist_from friend@somedomain.com

# Blacklist specific email addresses
blacklist_from baduser@spammerdomain.com
blacklist_from *@verybaddomain.net

# Whitelist by SPF. This will only whitelist based on the MAIL FROM
# This can protect against spoofed 'From:' headers
# whitelist_spf  dkim@trusted-domain.example.com

# or: Whitelist DKIM signatures. Note that this does not necessarily
# mean that the address in the From: header is trusted, just that
# the DNS record agrees that the message actually originated from
# someone authorized to send email from that domain.
# whitelist_dkim *@trusted-domain.example.com

# whitelist_auth  sender@example.com  # whitelist only if SPF, DKIM, etc passes

Explanation:

  • `whitelist_from`: Specifies email addresses or domains that should always be considered legitimate. Using `*@example.com` whitelists all emails from the `example.com` domain.
  • `blacklist_from`: Specifies email addresses or domains that should always be considered spam.
  • `whitelist_spf`: Whitelists based on SPF (Sender Policy Framework) records. This verifies that the sending server is authorized to send emails on behalf of the domain in the `MAIL FROM` address (the envelope sender).
  • `whitelist_dkim`: Whitelists based on DKIM (DomainKeys Identified Mail) signatures. This verifies the authenticity and integrity of the email content.
  • `whitelist_auth`: Only whitelists if SPF, DKIM or other authentication methods passed successfully.

Enabling Additional Rule Sets and Updating Rules

SpamAssassin uses a set of rules to identify spam. You can enable additional rule sets and regularly update the rules to keep your spam filter effective against evolving spam techniques.

SpamAssassin rules are usually updated automatically using `sa-update`. You can force an update with:

sudo sa-update

Enable or disable rules by editing the `/etc/spamassassin/v310.pre` file (or the appropriate file name for your version of SpamAssassin, they all start with `v3`). For example, to enable the `Razor2` rules, uncomment (remove the `#` at the beginning of the line) the following line:

loadplugin Mail::SpamAssassin::Plugin::Razor2

However, directly editing files is not recommended. Instead, create your own configuration file (e.g., `/etc/spamassassin/custom.cf`) and add your customizations there. This prevents your changes from being overwritten during updates. For example, to adjust the score of a specific rule:

# /etc/spamassassin/custom.cf

score HTML_MESSAGE            0.1  # Reduce score for HTML messages
score URIBL_BLAHBLAH          3.5  # Increase score for URIBL_BLAHBLAH rule

Restart SpamAssassin after making changes to rule files: `sudo systemctl restart spamassassin`.

FeatureDescriptionConfiguration
Scoring ThresholdsControls the sensitivity of spam detection.`required_score` in `/etc/spamassassin/local.cf`
Whitelisting/BlacklistingAllows explicit trust/distrust of senders.`whitelist_from`, `blacklist_from` in `/etc/spamassassin/local.cf`
Rule UpdatesEnsures SpamAssassin uses the latest spam detection rules.`sa-update` command

Dovecot Sieve Integration: User-Level Spam Filtering

While Postfix and SpamAssassin provide server-wide spam filtering, Dovecot’s Sieve filtering allows users to customize how spam is handled in their individual mailboxes. Sieve is a scripting language designed for email filtering, enabling users to automatically move spam to a dedicated folder, discard it entirely, or perform other actions based on specific criteria.

Installing and Configuring Dovecot Sieve

First, ensure that the Dovecot Sieve plugin is installed. The package name might vary depending on your Linux distribution (e.g., `dovecot-sieve`, `dovecot-managesieve`).

sudo apt-get install dovecot-sieve  # Debian/Ubuntu
sudo yum install dovecot-sieve      # CentOS/RHEL

Next, configure Dovecot to enable Sieve support. Edit the `/etc/dovecot/dovecot.conf` file and add or modify the following settings:

# /etc/dovecot/dovecot.conf

protocols = imap pop3 lmtp

protocol lmtp {
  mail_plugins = $mail_plugins sieve
}

protocol imap {
  mail_plugins = $mail_plugins sieve
}

protocol pop3 {
  mail_plugins = $mail_plugins sieve
}

mail_plugins = $mail_plugins sieve

plugin {
  sieve = /var/lib/dovecot/sieve/%u.sieve
  sieve_dir = /var/lib/dovecot/sieve/
}

Explanation:

  • `protocols`: Specifies the email protocols to enable (IMAP, POP3, LMTP). LMTP (Local Mail Transfer Protocol) is used for local delivery.
  • `protocol lmtp { mail_plugins = $mail_plugins sieve }`: Enables the Sieve plugin for LMTP. This is necessary if Postfix delivers emails to Dovecot using LMTP.
  • `protocol imap { mail_plugins = $mail_plugins sieve }`: Enables the Sieve plugin for IMAP.
  • `protocol pop3 { mail_plugins = $mail_plugins sieve }`: Enables the Sieve plugin for POP3.
  • `mail_plugins = $mail_plugins sieve`: Ensures the Sieve plugin is enabled globally.
  • `plugin { sieve = /var/lib/dovecot/sieve/%u.sieve }`: Specifies the location of the user’s Sieve script. `%u` is a placeholder for the username. This means each user will have a separate sieve script.
  • `plugin { sieve_dir = /var/lib/dovecot/sieve/ }`: Specifies the directory where Sieve scripts are stored.

After modifying `dovecot.conf`, restart Dovecot: `sudo systemctl restart dovecot`.

Creating a Basic Sieve Script for Spam Filtering

Now, let’s create a basic Sieve script to move emails identified as spam by SpamAssassin to a user’s “Spam” folder. The Sieve script is typically named after the username with the `.sieve` extension and stored in the directory specified by `sieve_dir` in `dovecot.conf` (e.g., `/var/lib/dovecot/sieve/user@example.com.sieve`).

# /var/lib/dovecot/sieve/user@example.com.sieve

require "fileinto";

# Check for SpamAssassin's X-Spam-Flag header
if header :contains "X-Spam-Flag" "YES" {
  fileinto "Spam";
  stop;
}

# Default action: Deliver to inbox
else {
  fileinto "INBOX";
}

Explanation:

  • `require “fileinto”;`: Loads the `fileinto` extension, which allows you to move emails to different folders.
  • `if header :contains “X-Spam-Flag” “YES” { … }`: Checks if the email header `X-Spam-Flag` contains the value `”YES”`. SpamAssassin typically adds this header to emails it identifies as spam.
  • `fileinto “Spam”;`: Moves the email to the “Spam” folder if the `X-Spam-Flag` header is present.
  • `stop;`: Stops processing further rules in the Sieve script. This is important to prevent the email from being processed by other rules.
  • `else { fileinto “INBOX”; }`: If the email is not identified as spam (i.e., the `X-Spam-Flag` header is not present), it’s delivered to the user’s inbox.

Compiling the Sieve Script:

Sieve scripts need to be compiled before they can be used. Use the `sievec` command to compile the script:

sudo sievec /var/lib/dovecot/sieve/user@example.com.sieve

This command will create a compiled version of the script with the `.svbin` extension in the same directory. Ensure the dovecot user has read access to both the `.sieve` and `.svbin` files.

Important: Dovecot needs to know what the active script is. One can do this by using a symbolic link. For example, if a user wants to activate the script at `/var/lib/dovecot/sieve/user@example.com.sieve`, one needs to create a symbolic link at `/var/lib/dovecot/sieve/user@example.com.sieve` named `user@example.com.sieve`. Let us show that using `ln -s` command:

ln -s /var/lib/dovecot/sieve/user@example.com.sieve /var/lib/dovecot/sieve/user@example.com

Advanced Sieve Scripting (Optional)

Sieve offers much more than just basic spam filtering. You can create complex rules to filter emails based on various criteria, such as sender, recipient, subject, or content. Here’s an example of a more advanced Sieve script:

# /var/lib/dovecot/sieve/user@example.com.sieve

require ["fileinto", "imap4flags"];

# Move spam to Spam folder
if header :contains "X-Spam-Flag" "YES" {
  fileinto "Spam";
  setflag "\\Seen"; # Mark as read
  stop;
}

# Move emails from specific sender to a folder
if header :is "From" "boss@example.com" {
  fileinto "Important";
  stop;
}

# Discard emails with specific subject (Example: unsubscribe)
if header :contains "Subject" "unsubscribe" {
  discard;
  stop;
}

# Default action: Deliver to inbox
else {
  fileinto "INBOX";
}

Explanation:

  • `require [“fileinto”, “imap4flags”];`: Loads the `fileinto` and `imap4flags` extensions. `imap4flags` allows to modify IMAP flags like `\Seen` (read).
  • `setflag “\\Seen”;`: Marks the email as read after moving it to the “Spam” folder.
  • `if header :is “From” “boss@example.com” { … }`: Moves emails from `boss@example.com` to the “Important” folder. `:is` performs an exact match.
  • `if header :contains “Subject” “unsubscribe” { … }`: Discards emails containing “unsubscribe” in the subject line.
  • `discard;`: Discards the email without delivering it to any folder.

Remember to compile the Sieve script after making changes: `sudo sievec /var/lib/dovecot/sieve/user@example.com.sieve` and ensure symbolic link is properly set.

Expert Tip: Educate users on how to create and manage their own Sieve scripts. This empowers them to customize their spam filtering preferences and reduces the burden on system administrators.

Email Security Consultant

Testing and Troubleshooting Your Spam Filtering Setup

After configuring Postfix, SpamAssassin, and Dovecot Sieve, thorough testing is essential to ensure that your spam filtering system is working correctly. This section provides guidance on testing your setup and troubleshooting common issues.

Testing SpamAssassin Integration

The easiest way to test SpamAssassin is to send an email containing a known spam signature. SpamAssassin provides a test string that you can include in the body of an email:

XJS*C4JDBQADN1NSV7CQMV6QGTOH!BF3IN!HBB*84JHDQADN1NSV7CQMV6QGTOH!BF3IN!HBB*

Send an email to yourself including this string in the body. Then, check the email’s headers. You should see headers added by SpamAssassin, such as:

X-Spam-Flag: YES
X-Spam-Score: 10.5
X-Spam-Level: ++++++++++
X-Spam-Status: Yes, score=10.5 required=5.0 tests=AWL,BAYES_99,HTML_MESSAGE,
	      RAZOR2_CF_RANGE_51_100,RAZOR2_CHECK,SPF_PASS,URIBL_BLAHBLAH
	      autolearn=spam autolearn_force=no version=3.4.2

Explanation:

  • `X-Spam-Flag: YES`: Indicates that SpamAssassin has identified the email as spam.
  • `X-Spam-Score`: The overall spam score assigned by SpamAssassin.
  • `X-Spam-Level`: A visual representation of the spam score (number of plus signs).
  • `X-Spam-Status`: Detailed information about the spam analysis, including the score, the required score for spam classification, the tests that were triggered, and whether the email was automatically learned as spam.

If you don’t see these headers, check the Postfix logs (`/var/log/mail.log` or `/var/log/maillog`) for errors related to SpamAssassin integration. Ensure that SpamAssassin (`spamd`) is running and that Postfix is correctly configured to forward emails to SpamAssassin.

Testing Dovecot Sieve Integration

<

Share this article