All posts All posts by this author Paper color Change page color Announcements

Antispam gateway with postfix and before-queue-filter-with-amavisd

This is a configuration that we use as an antispam gateway for an internal mail server. The antispam gateway receives email from internet, scans it for spam and virus, if found, rejects the bad email during smtp conversation with the spammer. This prevents backscatter emails, and also doesn't require you to silently drop emails with high spam score. According to EU directives, silently discarding email after spam is found can even be unlawful!

we use postfix and amavis for incoming and outgoing mail and we reject spam and viruses during the smtp session. We have a list of all our email recipients and have put them in /etc/postfix/relay_recipients. This is our setup:

In /etc/postfix/master.cf we have added this:

smtp       inet  n       -       n       -       40     smtpd
        -o smtpd_proxy_filter=127.0.0.1:10024
        -o smtpd_client_connection_count_limit=20
        -o smtpd_proxy_timeout=300s
        -o smtpd_proxy_options=speed_adjust

127.0.0.1:10025 inet n   -       n       -       -      smtpd
        -o smtpd_authorized_xforward_hosts=127.0.0.0/8
        -o smtpd_client_restrictions=
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o smtpd_data_restrictions=
        -o mynetworks=127.0.0.0/8
        -o receive_override_options=no_unknown_recipient_checks

In /etc/postfix/main.cf:

alias_maps = hash:/etc/aliases
mydomain = 
myorigin = 
myhostname = gateway.example.com
mynetworks = 127.0.0.1/8
message_size_limit = 52428800
local_transport = error:no local mail delivery
mydestination =
local_recipient_maps =
virtual_alias_maps = hash:/etc/postfix/virtual
transport_maps = hash:/etc/postfix/transport
relay_domains = hash:/etc/postfix/relay_domains
relay_recipient_maps = hash:/etc/postfix/relay_recipients
unknown_client_reject_code = 550
smtpd_client_restrictions =
 permit_mynetworks,
 reject_unknown_client_hostname
 smtpd_helo_required = yes
smtpd_sender_restrictions =
 permit_mynetworks,
 reject_non_fqdn_sender
 reject_unknown_sender_domain
smtpd_recipient_restrictions =
 permit_mynetworks
 reject_non_fqdn_recipient
 reject_unauth_destination
 reject_unknown_recipient_domain
strict_rfc821_envelopes = yes
recipient_delimiter =

In /etc/amavis/conf.d/50-user we changed:

use strict;


@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);


$banned_filename_re = undef;


$sa_spam_subject_tag = '[SPAM]  ';
$sa_tag_level_deflt  = -999;      # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 5.0;       # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.0;       # triggers spam evasive actions
$sa_dsn_cutoff_level = 6.0;       # spam level beyond which a DSN is not sent
$sa_quarantine_cutoff_level = 6;  # spam level beyond which quarantine is off


$final_virus_destiny      = D_REJECT;
$final_banned_destiny     = D_REJECT;
$final_spam_destiny       = D_REJECT;
$final_bad_header_destiny = D_PASS;

$bad_header_quarantine_to = undef;
$virus_quarantine_to = undef;

@score_sender_maps = ({
   '.' => [
      read_hash("/etc/amavis/sender_scores_sitewide")
          ]
});


$log_level = 1;               # verbosity 0..5
$sa_debug = 1;

@local_domains_maps = (read_hash("/etc/postfix/relay_domains"));


$max_servers = 20;            # number of pre-forked children (2..15 is common)

 #------------ Do not modify anything below this line -------------
1;  # ensure a defined return

The advantage of this setup is that when your spam filters detect an email as spam, it rejects it during SMTP time, so that the sender gets a bounce notification. You also don't have to silently discard/quarantine any virus laden email.

The disadvantage of this setup is that it is suited for a low to medium volume site, and it doesn't do any DNSBL based checks at MTA level. If you are getting multiple incoming SMTP connections (more than max_servers setting in /etc/amavis/conf.d/50-user), your server will cause subsequent smtp connections to wait for current requests to complete. It won't help to use DNSBL in MTA because your amavisd processes will still spawn. Now-a-days postscreen is a better defense to deter the zombies and bots, as well as any DNSBL scoring and rejection at SMTP time. I will post a postscreen based setup later.

Software Solutions