Mail server for a VPS: Postfix, Dovecot, Spamassassin, policyd-weight

Full featured mail server with memory footprint small enogh even for a VPS, with dovecot, postfix, spamassassin, clamav, policyd-weight with all the configs you need.


  1. UPDATE, 2014-12-18
  2. UPDATE, 2012-02-25
  • install & configure mysql server
    1. SQL scheme for our mail server
  • the vmail user
    1. install dovecot
    2. update: config for dovecot 2.X/etc/dovecot/dovecot.conf
    3. /etc/dovecot/dovecot-sql.conf
    4. /etc/dovecot/sieve/sieve.default
  • postfix
    1. install postfix
    2. /etc/postfix/main.cf
    3. /etc/postfix/master.cf
    4. /etc/postfix/mysql-virtual_domains.cf
    5. /etc/postfix/mysql-virtual_email2email.cf
    6. /etc/postfix/mysql-virtual_forwardings.cf
    7. /etc/postfix/mysql-virtual_mailboxes.cf
    8. /etc/postfix/dynamicmaps.cf
    9. /etc/postfix/sasl/smtpd.conf
  • policyd-weight
    1. /etc/policyd-weight.conf
  • Spamassassin
    1. install SpamAssassin and ClamAV
  • Afterwords
  • UPDATE, 2014-12-18

    I’ve recently wrote an updated version of a similar, better setup.

    UPDATE, 2012-02-25

    I’ve updated my system to Dovecot 2, and removed ClamAV from the whole line. I haven’t received any virus mails in the last 4 years, also they usually end up as spam, and ClamAV was eating up ~300 MB memory total (50 RAM, 250 swap).

    For nearly 5 years, I always used Virtualmin GPL everywhere I could, because I did not had to configure many features myself, it came with pre-configs and really good backend scripts. But as always, it had a price: memory and CPU usage, what is luxury in the world of VPS‘.

    I tried to look for the best solution to handle emails, filtering them for spam and virus, and the only system I came across with was always Amavisd. amavisd is basically a wrapper for spam and virus filtering: it can simultaneously use more than one for both purpose, and most people say it’s a nice program. Unfortunately, I tried to configure it, not just use it, and for me it was hell. I’ve known that Perl is somewhat evil, but configuring amavisd is a mess at all, so I searched for a way to bypass it.

    It wasn’t easy, but in the depth of the postfix forums, I’ve found out, that postfix is able to pass the mail to a program than catch the output and pass to another program and so on. The trickiest part was to include ClamAV filtering in the way, because ClamAV does not passes the mail back, so the filtering had to be included into Spamassassin.

    I’ve also found, that Virtualmin uses it’s configured version of Procmail, which was the most hard to replace. The reason for the replacement was that I haven’t find any plugin for Roundcube to manage the server-side filtering of procmail. Since Dovecot has already added a version of Sieve to it’s core combined with Dovecot’s Local Delivery Agent, it could replace, or could even be a better solution than Procmail. Also Sieve can be accessed from outside, from, for example from Thunderbird with a plugin.

    Probably for the best security Virtualmin used local users for everything. While this is an easy and truly secure solution, for a bit more flexibility I used MySQL as source of data. Per user SpamAssassin could also be stored in MySQL and RoundCube has a plugin for this purpose too.

    install & configure mysql server

    This is not the topic for a mysql server install, there are plenty of tutorials on this topic.

    SQL scheme for our mail server

    
    --
    -- Table structure for table `domains`
    --
    
    CREATE TABLE IF NOT EXISTS `domains` (
      `domain` varchar(50) NOT NULL,
      PRIMARY KEY (`domain`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `forwardings`
    --
    
    CREATE TABLE IF NOT EXISTS `forwardings` (
      `source` varchar(80) NOT NULL,
      `destination` text NOT NULL,
      PRIMARY KEY (`source`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `transport`
    --
    
    CREATE TABLE IF NOT EXISTS `transport` (
      `domain` varchar(128) NOT NULL DEFAULT '',
      `transport` varchar(128) NOT NULL DEFAULT '',
      UNIQUE KEY `domain` (`domain`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- --------------------------------------------------------
    
    --
    -- Table structure for table `users`
    --
    
    CREATE TABLE IF NOT EXISTS `users` (
      `email` varchar(80) NOT NULL,
      `password` varchar(255) NOT NULL,
      PRIMARY KEY (`email`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    the vmail user

    We’re about to use a system user, named vmail for all our purposes. All the mails will be stored under the name of this user, with private rights.

    
    groupadd --gid 5000 vmail
    adduser -uid 5000 -gid 5000 --home /vmail --create-home vmail
    

    <h2dovecot I start with Dovecot, because even Postfix will rely on it in the authentication process. Also, Dovecot is going to be the local delivery agent (LDA) in order to use Sieve.
    POP3 is already out of sight, don’t search for it ;)

    install dovecot

    
    apt-get install dovecot-common dovecot-imapd
    

    update: config for dovecot 2.X/etc/dovecot/dovecot.conf

    
    #
    # Main
    #
    disable_plaintext_auth = no
    
    log_timestamp = "%Y-%m-%d %H:%M:%S "
    login_greeting = webportfolio.hu
    
    mail_location = maildir:~/Maildir:INDEX=/var/lib/dovecot/index/%u:CONTROL=/var/lib/dovecot/control/%u
    mail_privileged_group = mail
    
    protocols = imap sieve
    
    ssl_cert = 
    <summary><ins datetime="2012-02-25T06:27:20+00:00">update: config for dovecot 1.3</ins>/etc/dovecot/dovecot.conf</summary>
    ```perl
    
    ## Dovecot configuration file
    protocols = imap imaps managesieve
    disable_plaintext_auth = no
    
    ##
    ## Logging
    ##
    
    log_timestamp = "%Y-%m-%d %H:%M:%S "
    syslog_facility = mail
    
    ##
    ## SSL settings
    ##
    ssl = yes
    ssl_cert_file = /etc/ssl/your_domain.crt
    ssl_key_file  = /etc/ssl/your_domain.key
    
    ##
    ## Login processes
    ##
    login_process_size = 64
    login_processes_count = 4
    login_max_processes_count = 32
    login_max_connections = 32
    login_greeting = hi
    
    ##
    ## Mailbox locations and namespaces
    ##
    
    mail_location = maildir:~/Maildir:INDEX=/var/lib/dovecot/index/%u:CONTROL=/var/lib/dovecot/control/%u
    mail_privileged_group = mail
    
    ##
    ## IMAP specific settings
    ##
    
    protocol imap {
        imap_client_workarounds = outlook-idle
    }
    
    ##
    ## MANAGESIEVE specific settings
    ##
    
    protocol managesieve {
        login_executable = /usr/lib/dovecot/managesieve-login
        mail_executable = /usr/lib/dovecot/managesieve
    }
    
    ##
    ## LDA specific settings
    ##
    
    auth_executable = /usr/lib/dovecot/dovecot-auth
    
    protocol lda {
        postmaster_address = root@localhost
    
        # you going to need to create this file by hand with 0777 rights, I could not make it writeable any other way
        log_path = /var/log/dovecot.log
        info_log_path = /var/log/dovecot.log
    
        mail_plugins = sieve
    }
    
    ##
    ## Authentication processes
    ##
    
    auth default {
        user = root
    
        passdb sql {
            args = /etc/dovecot/dovecot-sql.conf
        }
    
        userdb static {
            args = uid=5000 gid=5000 home=/vmail/%d/%n allow_all_users=yes
        }
    
        socket listen {
            master {
                path = /var/run/dovecot/auth-master
                mode = 0600
                user = vmail
            }
    
            client {
                path = /var/spool/postfix/private/auth
                mode = 0660
                user = postfix
                group = postfix
            }
        }
    }
    
    ##
    ## Plugin settings
    ##
    
    plugin {
        # the /etc/dovecot/sieve/sieve.default will run _before_ any user defined sieve scripts
        sieve_before = /etc/dovecot/sieve/sieve.default
    }
    

    /etc/dovecot/dovecot-sql.conf

    
    driver = mysql
    connect = host=127.0.0.1 dbname=mail_mysql_db user=mail_mysql_user password=mail_mysql_password
    default_pass_scheme = CRYPT
    password_query = SELECT email as user, password FROM users WHERE email='%u';
    

    /etc/dovecot/sieve/sieve.default

    
    require "fileinto";
    
        if header :contains "X-Spam-Virus" "Yes" {
            fileinto "spam";
            stop;
        }
    
        if header :contains "X-Spam-Status" "Yes" {
            fileinto "spam";
            stop;
        }
    

    postfix

    Postfix is the SMTP server; this is the one that communicates with the other mail servers, so it also receives and sends all the messages.

    install postfix

    
    apt-get install postfix postfix-mysql
    

    /etc/postfix/main.cf

    
    smtpd_banner = your_mailserver_domain
    biff = no
    append_dot_mydomain = no
    delay_warning_time = 4h
    readme_directory = no
    
    alias_maps = hash:/etc/aliases
    alias_database = hash:/etc/aliases
    
    virtual_alias_domains =
    virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf
    virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf
    virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf
    virtual_mailbox_base = /vmail
    virtual_uid_maps = static:5000
    virtual_gid_maps = static:5000
    virtual_create_maildirsize = yes
    virtual_maildir_extended = yes
    proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps
    virtual_transport=dovecot
    dovecot_destination_recipient_limit=1
    
    local_recipient_maps = proxy:unix:passwd.byname $alias_maps
    
    smtpd_tls_cert_file = /etc/ssl/your_domain.crt
    smtpd_tls_key_file  = /etc/ssl/your_domain.key
    smtpd_tls_note_starttls = yes
    smtpd_use_tls=yes
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    
    myhostname = your_mailserver_domain
    myorigin = your_mailserver_domain
    mydestination = your_mailserver_domain your_mailserver_name localhost.localdomain locahost
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    
    mailbox_size_limit = 0
    message_size_limit = 52428800
    recipient_delimiter = +
    inet_interfaces = all
    
    smtpd_sasl_auth_enable = yes
    smtpd_sasl_security_options = noanonymous
    broken_sasl_auth_clients = yes
    smtpd_sasl_authenticated_header = yes
    smtpd_sasl_type = dovecot
    smtpd_sasl_path = private/auth
    smtpd_tls_security_level = may
    
    maximal_queue_lifetime = 1d
    queue_run_delay = 500s
    minimal_backoff_time = 500s
    bounce_queue_lifetime = 1d
    
    smtpd_helo_required = yes
    smtpd_helo_restrictions = permit_mynetworks,
        reject_invalid_hostname,
        permit
    
    smtpd_recipient_restrictions =  permit_mynetworks,
        permit_sasl_authenticated,
        reject_invalid_hostname,
        reject_non_fqdn_hostname,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        reject_unauth_pipelining,
        reject_unauth_destination,
        check_policy_service inet:127.0.0.1:12525,
        permit
    

    /etc/postfix/master.cf

    
    smtp      inet  n       -       -       -       -       smtpd
    smtps     inet  n       -       -       -       -       smtpd
    pickup    fifo  n       -       -       60      1       pickup
    cleanup   unix  n       -       -       -       0       cleanup
    qmgr      fifo  n       -       n       300     1       qmgr
    tlsmgr    unix  -       -       -       1000?   1       tlsmgr
    rewrite   unix  -       -       -       -       -       trivial-rewrite
    bounce    unix  -       -       -       -       0       bounce
    defer     unix  -       -       -       -       0       bounce
    trace     unix  -       -       -       -       0       bounce
    verify    unix  -       -       -       -       1       verify
    flush     unix  n       -       -       1000?   0       flush
    proxymap  unix  -       -       n       -       -       proxymap
    proxywrite unix -       -       n       -       1       proxymap
    smtp      unix  -       -       -       -       -       smtp
    relay     unix  -       -       -       -       -       smtp
      -o smtp_fallback_relay=
    showq     unix  n       -       -       -       -       showq
    error     unix  -       -       -       -       -       error
    retry     unix  -       -       -       -       -       error
    discard   unix  -       -       -       -       -       discard
    local     unix  -       n       n       -       -       local
    virtual   unix  -       n       n       -       -       virtual
    lmtp      unix  -       -       -       -       -       lmtp
    anvil     unix  -       -       -       -       1       anvil
    scache    unix  -       -       -       -       1       scache
    
    dovecot   unix  -       n       n        -      -       pipe
      flags=DRhu user=vmail:vmail argv=/usr/bin/spamc -e /usr/lib/dovecot/deliver -d ${recipient} -f {sender}
    
    maildrop  unix  -       n       n       -       -       pipe
      flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
    
    uucp      unix  -       n       n       -       -       pipe
      flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
    
    ifmail    unix  -       n       n       -       -       pipe
      flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
    
    bsmtp     unix  -       n       n       -       -       pipe
    
      flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
    
    scalemail-backend unix - n      n       -       2       pipe
      flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
    
    mailman   unix  -       n       n       -       -       pipe
      flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
      ${nexthop} ${user}
    

    /etc/postfix/mysql-virtual_domains.cf

    
    user = mail_mysql_user
    password = mail_mysql_password
    dbname = mail_mysql_db
    hosts = 127.0.0.1
    query = SELECT domain AS virtual FROM domains WHERE domain='%s'
    

    /etc/postfix/mysql-virtual_email2email.cf

    
    user = mail_mysql_user
    password = mail_mysql_password
    dbname = mail_mysql_db
    hosts = 127.0.0.1
    query = SELECT email FROM users WHERE email='%s
    

    /etc/postfix/mysql-virtual_forwardings.cf

    
    user = mail_mysql_user
    password = mail_mysql_password
    dbname = mail_mysql_db
    hosts = 127.0.0.1
    query = SELECT destination FROM forwardings WHERE source='%s'
    

    /etc/postfix/mysql-virtual_mailboxes.cf

    
    user = mail_mysql_user
    password = mail_mysql_password
    dbname = mail_mysql_db
    hosts = 127.0.0.1
    query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s'
    

    /etc/postfix/dynamicmaps.cf

    
    tcp /usr/lib/postfix/dict_tcp.so        dict_tcp_open   
    mysql   /usr/lib/postfix/dict_mysql.so      dict_mysql_open 
    

    /etc/postfix/sasl/smtpd.conf

    
    pwcheck_method: saslauthd
    mech_list: plain login
    allow_plaintext: true
    auxprop_plugin: mysql
    sql_hostnames: 127.0.0.1
    sql_user: mail_mysql_user
    sql_passwd: mail_mysql_password
    sql_database: mail_mysql_db
    sql_select: select password from users where email = '%u'
    

    policyd-weight

    I’ve already wrote a post about policyd-weight and why it is better than blocklists in postfix config directly, so this is only my current config file and the install.
    This config is tweaked at some points but I honestly forgot, what I configured exactly, so here is the full version.

    apt-get install policyd-weight

    /etc/policyd-weight.conf

    
    # ----------------------------------------------------------------
    #  policyd-weight configuration (defaults) Version 0.1.14 beta-17
    # ----------------------------------------------------------------
    
    # 1 or 0 - don't comment
    $DEBUG = 0;
    
    $REJECTMSG = "550 Mail appeared to be SPAM or forged. Ask your Mail/DNS-Administrator to correct HELO and DNS MX settings or to get removed from DNSBLs";
    
    $REJECTLEVEL = 4; # Mails with scores which exceed this REJECTLEVEL will be rejected
    
    # A space separated case-sensitive list of strings on which if found in the $RET logging-string policyd-weight changes
    # its action to $DEFER_ACTION in case.
    # of rejects.
    # USE WITH CAUTION!
    # DEFAULT: "IN_SPAMCOP= BOGUS_MX="
    $DEFER_STRING = 'IN_SPAMCOP= BOGUS_MX=';
    
    # Possible values: DEFER_IF_PERMIT, DEFER_IF_REJECT,
    # 4xx response codes. See also access(5)
    # DEFAULT: 450
    $DEFER_ACTION = '450';
    
    # DEFER mail only up to this level
    # scores greater than DEFER_LEVEL will be
    # rejected
    # DEFAULT: 5
    $DEFER_LEVEL  = 5;
    
    $DNSERRMSG = '450 No DNS entries for your MTA, HELO and Domain. Contact YOUR administrator';
    
    # 1: ON, 0: OFF (default)
    # If ON request that ALL clients are only checked against RBLs
    $dnsbl_checks_only = 0;
    
    # specify a comma-separated list of regexps
    # for client hostnames which shall only be RBL checked.
    # This does not work for postfix' "unknown" clients.
    # The usage of this should not be the norm and is a tool for people which like to shoot in their own foot.
    # DEFAULT: empty
    @dnsbl_checks_only_regexps = (
    # qr/[^.]*(exch|smtp|mx|mail).*..*../,
    # qr/yahoo.com$/
    );
    
    # 1: ON (default), 0: OFF
    # When set to ON it logs only RBLs which affect scoring (positive or negative)
    $LOG_BAD_RBL_ONLY  = 1;
    
    ## DNSBL settings
    @dnsbl_score = (
        # host,hit score, miss score, log name
        'bl.spamcop.net',3,0,'bl.spamcop.net',
        'cbl.abuseat.org',  3,  0,  'cbl.abuseat.org',
        'dnsbl.njabl.org',  3,  0,  'dnsbl.njabl.org',
        'dnsbl.sorbs.net',  3,  0,  'dnsbl.sorbs.net',
        'zen.spamhaus.org', 3,  0,  'zen.spamhaus.org',
        'pbl.spamhaus.org', 3,  0,  'pbl.spamhaus.org',
        'list.dsbl.org',3,0,'list.dsbl.org',
    );
    
    # If Client IP is listed in MORE DNSBLS than this var, it gets REJECTed immediately
    $MAXDNSBLHITS  = 3;
    
    # alternatively, if the score of DNSBLs is ABOVE this level, reject immediately
    $MAXDNSBLSCORE = 9;
    
    $MAXDNSBLMSG = '550 Az levelezoszerveruk IP cime tul sok spamlistan talahato, kerjuk ellenorizze! / Your MTA is listed in too many DNSBLs; please check.';
    
    ## RHSBL settings
    @rhsbl_score = (
        'multi.surbl.org',4,0,'multi.surbl.org',
        'rhsbl.ahbl.org',4,0,'rhsbl.ahbl.org',
        'dsn.rfc-ignorant.org',3.5,0,'dsn.rfc-ignorant.org',
        'postmaster.rfc-ignorant.org', 0.1,0,'postmaster.rfc-ignorant.org',
        'abuse.rfc-ignorant.org',0.1,0,'abuse.rfc-ignorant.org'
    );
    
    # skip a RBL if this RBL had this many continuous errors
    $BL_ERROR_SKIP = 2;
    
    # skip a RBL for that many times
    $BL_SKIP_RELEASE = 10;
    
    ## cache stuff
    # must be a directory (add trailing slash)
    $LOCKPATH = '/var/run/policyd-weight/';
    
    # socket path for the cache daemon.
    $SPATH = $LOCKPATH.'/polw.sock';
    
    # how many seconds the cache may be idle before starting maintenance routines
    #NOTE: standard maintenance jobs happen regardless of this setting.
    $MAXIDLECACHE = 60;
    
    # after this number of requests do following maintenance jobs: checking for config changes
    $MAINTENANCE_LEVEL = 5;
    
    # negative (i.e. SPAM) result cache settings ##################################
    
    # set to 0 to disable caching for spam results. To this level the cache will be cleaned.
    $CACHESIZE = 2000;
    
    # at this number of entries cleanup takes place
    $CACHEMAXSIZE = 4000;
    
    $CACHEREJECTMSG  = '550 temporarily blocked because of previous errors';
    
    # after NTTL retries the cache entry is deleted
    $NTTL = 1;
    
    # client MUST NOT retry within this seconds in order to decrease TTL counter
    $NTIME = 30;
    
    # positve (i.,e. HAM) result cache settings ###################################
    
    # set to 0 to disable caching of HAM. To this number of entries the cache will be cleaned
    $POSCACHESIZE = 1000;
    
    # at this number of entries cleanup takes place
    $POSCACHEMAXSIZE = 2000;
    
    $POSCACHEMSG = 'using cached result';
    
    #after PTTL requests the HAM entry must succeed one time the RBL checks again
    $PTTL = 60;
    
    # after $PTIME in HAM Cache the client must pass one time the RBL checks again.
    #Values must be nonfractal. Accepted time-units: s, m, h, d
    $PTIME = '3h';
    
    # The client must pass this time the RBL checks in order to be listed as hard-HAM
    # After this time the client will pass immediately for PTTL within PTIME
    $TEMP_PTIME = '1d';
    
    ## DNS settings
    
    # Retries for ONE DNS-Lookup
    $DNS_RETRIES = 1;
    
    # Retry-interval for ONE DNS-Lookup
    $DNS_RETRY_IVAL  = 5;
    
    # max error count for unresponded queries in a complete policy query
    $MAXDNSERR = 3;
    
    $MAXDNSERRMSG = 'passed - too many local DNS-errors';
    
    # persistent udp connection for DNS queries.
    #broken in Net::DNS version 0.51. Works with Net::DNS 0.53; DEFAULT: off
    $PUDP= 0;
    
    # Force the usage of Net::DNS for RBL lookups.
    # Normally policyd-weight tries to use a faster RBL lookup routine instead of Net::DNS
    $USE_NET_DNS  = 0;
    
    # A list of space separated NS IPs
    # This overrides resolv.conf settings
    # Example: $NS = '1.2.3.4 1.2.3.5';
    # DEFAULT: empty
    $NS  = '';
    
    # timeout for receiving from cache instance
    $IPC_TIMEOUT  = 2;
    
    # If set to 1 policyd-weight closes connections to smtpd clients in order to avoid too many
    #established connections to one policyd-weight child
    $TRY_BALANCE  = 0;
    
    # scores for checks, WARNING: they may manipulate eachother
    # or be factors for other scores.
    #  HIT score, MISS Score
    @client_ip_eq_helo_score = (1.5, -1.25 );
    @helo_score  = (1.5, -2 );
    @helo_score  = (0, -2 );
    @helo_from_mx_eq_ip_score= (1.5, -3.1  );
    @helo_numeric_score= (2.5,  0 );
    @from_match_regex_verified_helo= (1,-2 );
    @from_match_regex_unverified_helo = (1.6, -1.5  );
    @from_match_regex_failed_helo  = (2.5,  0 );
    @helo_seems_dialup = (1.5,  0 );
    @failed_helo_seems_dialup= (2, 0 );
    @helo_ip_in_client_subnet= (0,-1.2  );
    @helo_ip_in_cl16_subnet  = (0,-0.41 );
    #@client_seems_dialup_score  = (3.75, 0 );
    @client_seems_dialup_score  = (0, 0 );
    @from_multiparted  = (1.09, 0 );
    @from_anon= (1.17, 0 );
    @bogus_mx_score = (2.1,  0 );
    @random_sender_score  = (0.25, 0 );
    @rhsbl_penalty_score  = (3.1,  0 );
    @enforce_dyndns_score = (3, 0 );
    
    $VERBOSE = 0;
    
    # Switch on or off an additional
    # X-policyd-weight: header
    # DEFAULT: on
    $ADD_X_HEADER  = 1;
    
    # Fallback response in case the weighted check didn't return any response (should never appear).
    $DEFAULT_RESPONSE = 'DUNNO default';
    
    #
    # Syslogging options for verbose mode and for fatal errors.
    # NOTE: comment out the $syslog_socktype line if syslogging does not
    # work on your system.
    #
    
    # inet, unix, stream, console
    $syslog_socktype = 'unix';
    
    $syslog_facility = "mail";
    $syslog_options  = "pid";
    $syslog_priority = "info";
    $syslog_ident = "postfix/policyd-weight";
    
    #
    # Process Options
    #
    
    # User must be a username, no UID
    $USER = "polw";
    
    # specify GROUP if necessary
    # DEFAULT: empty, will be initialized as $USER
    $GROUP = "polw";
    
    # Upper limit if child processes
    $MAX_PROC = 5;
    
    # keep that minimum processes alive
    $MIN_PROC = 1;
    
    # The TCP port on which policyd-weight listens for policy requests from postfix
    $TCP_PORT = 12525;
    
    # IP-Address on which policyd-weight will listen for requests.
    # You may only list ONE IP here, if you want# to listen on all IPs you need to say 'all' here.
    # Default is '127.0.0.1'.
    # You need to restart policyd-weight if you change this.
    $BIND_ADDRESS = '127.0.0.1';
    
    # Maximum of client connections policyd-weight accepts
    # Default: 1024
    $SOMAXCONN = 128;
    
    # how many seconds a child may be idle before it dies.
    $CHILDIDLE = 30;
    
    $PIDFILE= "/var/run/policyd-weight.pid"; 
    

    Spamassassin

    SpamAssassin in this case means both SpamAssassin itself and ClamAV as well, since we’re going to use a plugin to get ClamAV to check for viruses in the spam filtering process as well.

    install SpamAssassin and ClamAV

    apt-get install spamassassin spamc

    To fire up the ClamAV plugin, Spamassassin already have a Wiki page for.

    Afterwords

    This is the base of my current mail system, and it’s doing it’s job quite well, but I don’t this it would stand as a very large traffic mailserver without some additional tweaks, for example, compiling the spamassassin rules, and so on. That’s for
    another day.