A mailserver with Postfix & Dovecot

Contents

I migrated a mailserver from an old-proprietary-stupid mailserver to Postfix, Dovecot, Spamassassin and Clavam antivirus etc etc. Sometimes internet is full of informations, sometimes internet give me some tips and sometimes - apparentely - no one is having my problems.

I wrote a guide - step by step - useful to configure a mail server in a real working environment with these features:

  • Postfix & Dovecot as MTA/MDA with TLS/SASL and IMAP/POP3/SMTP
  • Postfix manage RBL, Black List, DNSBL and header check
  • Postgrey manage greylisting
  • Spamassassin for filter spam
  • Clamav as antivirus
  • Sieve for filtering email messages
  • Postfixadmin as web-based front end for Postfix (with a mysql database & nginx)
  • Roundcube as web-based IMAP email client

SPF and firewall configuration will not be covered. These note contains also a working and valid solution to send encrypted mail to external mail server, like gmail/google, with trusted TLS certificate. Oh yes, Google view your email as encrypted & safe and you will have the Google lock :)

1
2
3
4
5
6
postfix/smtp[15887]: Trusted TLS connection established to gmail-smtp-in.l.google.com[64.233.166.27]:25:TLSv1.2 with
cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)

postfix/smtp[15887]: E55BDFFA63: to=<test.test@gmail.com>, relay=gmail-smtp-in.l.google.com[64.233.166.27]:25, delay=0.59,
delays=0.06/0.02/0.28/0.23, dsn=2.0.0, status=sent (250 2.0.0 OK 1516632052 n107si12756789wrb.247 - gsmtp)

About

This guide concern how to setup/install a mail server (Ubuntu or Debian) with:

  • Postfix & Dovecot as MTA/MDA with TLS/SASL and IMAP/POP3/SMTP
  • Postfix manage RBL, Black List, DNSBL and header check
  • Postgrey manage greylisting
  • Spamassassin for filter spam
  • Clamav as antivirus
  • Sieve for filtering email messages
  • Postfixadmin as web-based front end for Postfix (with a mysql database)
  • Roundcube as web-based IMAP email client

The full setup will work as:

–> Mail –> Whitelist –> Antivirus –> Sieve –> Client destination

or

–> Mail –> RBL/DNSBL –> Blacklist –> Greylist –> Antivirus –> Spamassassin –> Sieve –> Client destination

All files are available at : https://gist.github.com/kraba/b2de434204d95e54ecb8b11bec13c1e1

Postfix

Installation of required packages (for postfix and dovecot):

1
2
3
4
5
6
7
 apt-get install postfix nginx-common nginx-full python-certbot-nginx php7.0-common postfix-mysql  \
 php7.0-fpm php7.0-imap php7.0-mbstring  dovecot-imapd dovecot-pop3d  dovecot-mysql dovecot-lmtpd \
 libsasl2-2 sasl2-bin libsasl2-modules mysql-server mysql-client dovecot-sieve

 systemctl stop postfix
 systemctl stop nginx
 systemctl stop dovecot

Creation of the user for the mailboxes:

1
2
3
4
 groupadd -g 124 vmail
 useradd -r -u 150 -g mail -d /var/mail -s /sbin/nologin -c "Virtual mailbox" vmail
 chmod 770 /var/mail/
 chown vmail:mail /var/mail/

Please remember the UID and GID, if they are different (or you created a different one) you need to change it on postfix in the configuration files below. Now we’ve to create a database for postfix/postfixadmin (we’ll populate the DB in postfixadmin section):

1
2
3
4
 mysql -u root -p
   CREATE DATABASE postfix;
   CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'choose_a_password';
   GRANT ALL PRIVILEGES ON `postfix` . * TO 'postfix'@'localhost';

Cut & paste these lines on files (and backup old files - change mysite.org with correct domain).

Tip

Some features will be available during the next configurations, if we restart postfix now we could have some warning/errors

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
 cd /etc/postfix/
 vi main.cf

 biff = no
 myhostname = mail.mysite.org
 mydomain = mysite.org
 myorigin = /etc/mailname
 mydestination = $myhostname, localhost.$mydomain, localhost
 relayhost =
 mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
 mailbox_size_limit = 0
 recipient_delimiter = +
 inet_interfaces = all
 inet_protocols = ipv4
 alias_maps = hash:/etc/aliases
 #alias_database = hash:/etc/aliases
 #home_mailbox = Maildir/
 smtp_host_lookup = native
 # Do not append domain part to incomplete addresses (this is the MUA's job)
 append_dot_mydomain = no
 # Disable local transport (so that system accounts can't receive mail)
 local_transport = error:Local Transport Disabled
 compatibility_level=2

 ##### BLACKLIST
 # Deny VRFY recipient checks
 disable_vrfy_command = yes
 # log recipient address information when rejecting a client name/address or sender address
 smtpd_delay_reject = yes
 # Require HELO
 smtpd_helo_required = yes
 # Reject email if remote hostname is not in fully-qualified domain form. Usually bots sending email don’t have FQDN names
 # Reject all bots sending email from computers connected via DSL/ADSL computers. They don’t have valid internet hostname.
 smtpd_helo_restrictions = permit_mynetworks,
      reject_non_fqdn_hostname,
      reject_invalid_hostname,
      permit
 # Limit incoming or receiving email rate to avoid spam
 smtpd_error_sleep_time = 1s
 smtpd_soft_error_limit = 10
 smtpd_hard_error_limit = 20
 # Header check - rejected
 header_checks = regexp:/etc/postfix/header_check_file

 smtpd_relay_restrictions =
 	permit_mynetworks,
 	permit_sasl_authenticated,
 	defer_unauth_destination

 smtpd_recipient_restrictions =
         permit_mynetworks,
         permit_sasl_authenticated,
         reject_unauth_pipelining,
         reject_invalid_hostname,
 	reject_non_fqdn_hostname,
    	reject_non_fqdn_sender,
    	reject_non_fqdn_recipient,
         reject_unknown_sender_domain,
         reject_unauth_destination,
         reject_unknown_recipient_domain,
         reject_rbl_client zen.spamhaus.org,
       	reject_rbl_client bl.spamcop.net,
       	reject_rbl_client cbl.abuseat.org,
       	reject_rbl_client dnsbl.sorbs.net,
         reject_rbl_client psbl.surriel.com,
 	reject_rbl_client b.barracudacentral.org,
 	check_client_access cidr:/etc/postfix/client_checks,
         check_policy_service inet:127.0.0.1:10023,
 	permit

 smtpd_sender_restrictions =
         reject_non_fqdn_sender,
         reject_unknown_sender_domain,
 permit

 ##### TLS configuration
 # Just to remember :
 # smtpd --> handling/routing incoming mail
 # smtp --> delivering mail
 smtpd_use_tls = yes
 smtp_use_tls = yes
 # TSL Certificate location
 smtpd_tls_key_file = /etc/letsencrypt/live/mail.mysite.org/privkey.pem
 smtpd_tls_cert_file = /etc/letsencrypt/live/mail.mysite.org/fullchain.pem
 smtp_tls_key_file = /etc/letsencrypt/live/mail.mysite.org/privkey.pem
 smtp_tls_cert_file = /etc/letsencrypt/live/mail.mysite.org/fullchain.pem
 # CA location
 # https://askubuntu.com/questions/73865/postfix-gmail-certificate-verification-failed
 # prevent :  Untrusted TLS connection established
 smtp_tls_CApath = /etc/ssl/certs
 smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
 smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
 smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
 smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
 smtpd_tls_auth_only = yes
 smtpd_tls_received_header = yes
 smtpd_tls_session_cache_timeout = 3600s
 smtp_tls_note_starttls_offer = yes
 # Protocols
 smtp_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL
 smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL
 smtpd_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL
 smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
 smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
 smtp_tls_protocols = !SSLv2, !SSLv3
 smtpd_tls_protocols = !SSLv2, !SSLv3
 # Randomizer for key creation
 tls_random_source = dev:/dev/urandom
 # Encrypt all messages to 3rd-party email server
 smtpd_tls_security_level = may
 smtp_tls_security_level = may
 smtpd_tls_loglevel = 1
 smtp_tls_loglevel = 1
 # try to use strong ciphers
 smtpd_tls_ciphers = high
 smtp_tls_ciphers = high

 ##### SASL
 smtpd_sasl_auth_enable = yes
 smtpd_sasl_type = dovecot
 smtpd_sasl_path = private/auth
 smtpd_sasl_authenticated_header = yes
 #smtp_sasl_auth_enable = yes
 smtp_sasl_security_options = noanonymous
 smtpd_sasl_local_domain =
 broken_sasl_auth_clients = yes

 ##### Virtual mailbox settings
 # vmail id 150 - gid 124
 virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
 virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
 virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
 virtual_mailbox_base = /var/mail/vmail
 virtual_minimum_uid = 150
 virtual_uid_maps = static:150
 virtual_gid_maps = static:124
 virtual_transport = spamassassin
 # Spamassassin move spam to junk folder
 spamassassin_destination_recipient_limit = 1
 # Clamav AV
 content_filter = scan:127.0.0.1:10026
 receive_override_options = no_address_mappings

And now mySQL conf files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 vi mysql_relay_domains_maps.cf

 user = postfix
 password = postfix
 hosts = localhost
 dbname = postfix
 query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1' and active = '1'

 vi mysql_virtual_alias_maps.cf

 user = postfix
 password = postfix
 hosts = localhost
 dbname = postfix
 query = SELECT goto FROM alias WHERE address='%s' AND active = 1

 vi mysql_virtual_domains_maps.cf

 user = postfix
 password = postfix
 hosts = localhost
 dbname = postfix
 query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'

 vi mysql_virtual_mailbox_maps.cf

 user = postfix
 password = postfix
 hosts = localhost
 dbname = postfix
 query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1

We add the header_checks file with regular expressions and rules (use the gist link above for all the rules)

1
2
3
4
5
6
7
 vi /etc/postfix/header_check_file

 /^Subject: Virus Detected by Network Associates, Inc\. Webshield/       REJECT  Spam detected
 /^Subject: ---- Virus Detected ----$/                                   REJECT  Spam detected
 /^Subject: Virus detected$/                                             REJECT  Spam detected
 /^Subject: Virus Alert$/                                                REJECT  Spam detected
 ....

We are ready to modify these lines in master.cf (and backup old files):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 vi master.cf

 smtp      inet  n       -       y       -       -       smtpd
 #smtp      inet  n       -       y       -       1       postscreen
 #smtpd     pass  -       -       y       -       -       smtpd
 #dnsblog   unix  -       -       y       -       0       dnsblog
 #tlsproxy  unix  -       -       y       -       0       tlsproxy
 submission inet n       -       y       -       -       smtpd
   -o syslog_name=postfix/submission
   -o smtpd_tls_security_level=encrypt
   -o smtpd_sasl_auth_enable=yes
   -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
   -o milter_macro_daemon_name=ORIGINATING
   -o smtpd_sasl_type=dovecot
   -o smtpd_sasl_path=private/auth
   -o smtpd_tls_wrappermode=no

Dovecot

Cut & paste these lines and change mysite.org with correct domain:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 cd /etc/dovecot
 vi dovecot.conf

 auth_mechanisms = plain login
 first_valid_uid = 150
 last_valid_uid = 150
 first_valid_gid = 124
 last_valid_gid = 124
 postmaster_address = postmaster@mysite.org
 mail_location = maildir:/var/mail/vmail/%d/%n
 # https://wiki2.dovecot.org/VirtualUsers/Home
 # prevent lda(foo): Error: User foo doesn't have home dir set, disabling duplicate database
 mail_home = /var/mail/vmail/%d/%n
 mail_privileged_group = vmail
 namespace {
   inbox = yes
   mailbox Archive {
     auto = subscribe
     special_use = \Archive
   }
   mailbox Drafts {
     auto = subscribe
     special_use = \Drafts
   }
   mailbox Junk {
     auto = subscribe
     special_use = \Junk
   }
   mailbox Sent {
     auto = subscribe
     special_use = \Sent
   }
   mailbox Trash {
     auto = subscribe
     special_use = \Trash
   }
 }
 passdb {
   args = /etc/dovecot/dovecot-mysql.conf
   driver = sql
 }
 passdb {
   driver = pam
 }
 protocols = " imap lmtp pop3 "
 service auth {
   unix_listener /var/spool/postfix/private/auth {
     group = postfix
     mode = 0666
     user = postfix
   }
 }
 service lmtp {
     unix_listener /var/spool/postfix/private/lmtp {
         mode = 0600
         user = postfix
         group = postfix
   }
 }

 ssl_ca = </etc/letsencrypt/live/mail.mysite.org/cert.pem
 ssl_cert = </etc/letsencrypt/live/mail.mysite.org/fullchain.pem
 ssl_key = </etc/letsencrypt/live/mail.mysite.org/privkey.pem
 userdb {
   args = /etc/dovecot/dovecot-mysql.conf
   driver = sql
 }
 userdb {
   driver = passwd
 }

And create the dovecot-mysql file (check UID/GID of vmail)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 vi dovecot-mysql.conf

 driver = mysql
 connect = host=localhost dbname=postfix user=postfix password=postfixpass client_flags=0
 default_pass_scheme = MD5
 user_query = SELECT maildir, 150 AS uid, 124 AS gid FROM mailbox WHERE username = '%u'
 password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = '1'

And now we can setup sieve, a server-side mail filtering, to filter spam email. we want to move email from inbox to junk:

 mkdir /etc/dovecot/sieve
 vi /etc/dovecot/sieve/default.sieve

 require "fileinto";
 if header :contains "X-Spam-Flag" "YES" {
     fileinto "Junk";
 }

 chown vmail:vmail /etc/dovecot/sieve/ -R

Postfixadmin

Download the latest postfixadmin release at https://sourceforge.net/projects/postfixadmin/ and move it on /var/www :

1
2
 wget  -q -O - "http://package-postfixadmin.tar.gz " | sudo tar -xzf - -C /var/www
 mv /var/www/postfixadmin-etc-etc /var/www/postfixadmin

Edit the config file of postfixadmin and add/modify the following values:

1
2
3
4
5
6
7
8
 vi /var/www/postfixadmin/config.local.php

 $CONF['configured'] = true;
 $CONF['database_type'] = 'mysqli';
 $CONF['database_host'] = 'localhost';
 $CONF['database_user'] = 'postfix';
 $CONF['database_password'] = 'postfixpass';
 $CONF['database_name'] = 'postfix';

Ensure that the webserver is active (and well configured) and install postfixadmin:

1
2
3
 systemctl restart nginx

 http://www.mysite.org/postfixadmin/setup.php

Test if postfixadmin is available at http://www.mysite.org/postfixadmin/ and change the owner of templates_c directory:

1
2
 cd /var/www/postfixadmin/
 chown www-data:root -R templates_c

Test the setup

Now we can test the setup, create a mailbox on postfixadmin web page and verify if it’s correct:

1
2
3
4
5
 mysql -u postfix -p
 ...
 mysql> use postfix
 mysql> select * from mailbox; --> return the created user
 mysql> select * from domain; --> return the domain list

Quit from mysql and restart it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 systemctl restart postfix
 systemctl restart dovecot

 netstat -na | egrep "587|995|993"
 tcp        0      0 0.0.0.0:993             0.0.0.0:*               LISTEN     
 tcp        0      0 0.0.0.0:995             0.0.0.0:*               LISTEN     
 tcp        0      0 0.0.0.0:587             0.0.0.0:*               LISTEN  

 telnet localhost smtp
 Trying 127.0.0.1...
 Connected to localhost.
 Escape character is '^]'.
 220 mail.mysite.org ESMTP Postfix
 EHLO localhost
 250-mail.mysite.org
 250-PIPELINING
 250-SIZE 10240000
 250-ETRN
 250-STARTTLS
 250-AUTH PLAIN LOGIN
 250-ENHANCEDSTATUSCODES
 250-8BITMIME
 250-DSN
 250 SMTPUTF8

 telnet localhost imap
 Connected to localhost.
 Escape character is '^]'.
 * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS AUTH=PLAIN AUTH=LOGIN]
 Dovecot ready.
 1 LOGIN test@mysite.org testpass
 1 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY
 THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT
 CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES
 WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SPECIAL-USE] Logged in

 telnet localhost pop3
 Connected to localhost.
 Escape character is '^]'.
 +OK Dovecot ready.
 USER test@mysite.org
 +OK
 PASS testpass
 +OK Logged in.
 LIST
 +OK 38 messages:
 ....

Postgrey

Download and install it:

1
 apt-get install postgrey

check if it’s running:

1
2
 netstat -na | grep 10023
 tcp        0      0 127.0.0.1:10023         0.0.0.0:*               LISTEN  

To configure the greylist in postfix we’ve to add a line into main.cf:

Tip

The line is check_policy_service inet:127.0.0.1:10023 and it’ll be written after reject_unknown_recipient_domain

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 vi /etc/postfix/main.cf

 ...
 smtpd_recipient_restrictions =
         permit_mynetworks,
         permit_sasl_authenticated,
         reject_rbl_client zen.spamhaus.org,
         reject_rbl_client bl.spamcop.net,
         reject_rbl_client cbl.abuseat.org,
         reject_rbl_client dnsbl.sorbs.net,
         reject_unauth_pipelining,
         reject_invalid_hostname,
 	 reject_non_fqdn_hostname,
    	 reject_non_fqdn_sender,
    	 reject_non_fqdn_recipient,
         reject_unknown_sender_domain,
         reject_unauth_destination,
         reject_unknown_recipient_domain,
         check_policy_service inet:127.0.0.1:10023,
 	permit
  ...

We can set the delay time ( the minimum amount of time that must pass before Postgrey will accept a retry from a greylisted client ) , in this configuration 30 seconds:

1
2
3
 vi /etc/default/postgrey

 POSTGREY_OPTS="--inet=10023 --delay=30"

and in /etc/postgrey/whitelist_clients we can add a whitelist for mail client hostname, for example if we own also the domain testmail.com we write:

1
2
3
4
5
 vi /etc/postgrey/whitelist_clients

 ...
 # testmail.com hostname
 testmail.com

And then…restart postgrey and postfix:

1
2
 systemctl restart postfix
 systemctl restart postgrey

If a mail will be grey listed on log will appear lines like these :

1
2
3
4
5
6
 postfix/smtpd[]: connect from mx07.greydomain.it[1.1.1.1]
 postfix/smtpd[]: Anonymous TLS connection established from mx07.greydomain.it[1.1.1.1]: TLSv1.2  with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
 postgrey[]: action=greylist, reason=new, client_name=mx07.greydomain.it, client_address=1.1.1.1, sender=test@greydomain.it, recipient=test@mytest.org
 postfix/smtpd[]: NOQUEUE: reject: RCPT from mx07.greydomain.it[1.1.1.1]: 450 4.2.0 <test@mytest.org>: Recipient address rejected:Greylisted, see http://postgrey.schweikert.ch/help/mytest.org.html; from=<test@greydomain.it> to=<test@mytest.org> proto=ESMTP helo=<mx07.greydomain.it>
 ...
 postgrey[]: action=pass, reason=triplet found, delay=1314, client_name=mx05.greydomain.it, client_address=1.1.1.1,sender=test@greydomain.it, recipient=test@mytest.org

In mail header we can find this line:

1
 X-Greylist: delayed 1314 seconds by postgrey-1.35 at myserver; Wed, 10 Jan 2018 10:53:04 CET

Clamav

Install these packages :

1
 apt-get install clamav clamav-daemon clamsmtp

and launch:

1
2
3
 sed -i -e "s/^NotifyClamd/#NotifyClamd/g" /etc/clamav/freshclam.conf
 systemctl stop clamav-freshclam
 freshclam

and it will return an output like this:

1
2
3
4
 ClamAV update process started at Wed Jan 10 14:18:47 2018
 main.cvd is up to date (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr)
 daily.cvd is up to date (version: 24208, sigs: 1821204, f-level: 63, builder: neo)
 bytecode.cvd is up to date (version: 319, sigs: 75, f-level: 63, builder: neo)

yes, virus definition are updated! Edit the clamsmtpd.conf file and change some lines:

1
2
3
4
5
6
 vi /etc/clamsmtpd.conf

 # A header to add to all scanned email
 Header: X-AV-Checked: ClamAV using ClamSMTP
 # User to run as
 User: clamav

and run:

1
2
3
 chown -R clamav. /var/spool/clamsmtp
 chown -R clamav. /var/run/clamsmtp
 dpkg-reconfigure clamav-freshclam

modify main.cf and add the end of file:

1
2
3
4
5
 vi /etc/postfix/main.cf

 # Clamav AV
 content_filter = scan:127.0.0.1:10026
 receive_override_options = no_address_mappings

port 10026 is described in /etc/clamsmtpd.conf. Now edit master.cf and modify/add these lines

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 vi /etc/postfix/master.cf
  #### THESE LINES WILL BE MODIFED
  smtp      inet  n       -       y       -       -       smtpd
   -o content_filter=scan:127.0.0.1:10026
  #### THESE ARE NEW LINES
  # Antivirus
  scan      unix  -       -       n       -       16      smtp
         -o smtp_send_xforward_command=yes

 # For injecting mail back into postfix from the filter
 127.0.0.1:10025 inet  n -       n       -       16      smtpd
         -o content_filter=
         -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
         -o smtpd_helo_restrictions=
         -o smtpd_client_restrictions=
         -o smtpd_sender_restrictions=
         -o smtpd_recipient_restrictions=permit_mynetworks,reject
         -o mynetworks_style=host
         -o smtpd_authorized_xforward_hosts=127.0.0.0/8

and restart services:

1
 systemctl restart clamav-daemon clamsmtp postfix dovecot

Now we can test if Clamav it’s working: *just simple sending an email to test@mytest.org. If it’s working on header we can find ‘‘X-AV-Checked: ClamAV using ClamSMTP’’ just simple sending an email to test@mytest.org with this ‘‘fake’’ virus - http://www.eicar.org/86-0-Intended-use.html - on body message : X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H . According to Eicar this is a ‘‘EICAR Standard Anti-Virus Test File’’ and Clamav detect it as a virus and delete email. On log you can find these lines:

1
2
3
4
5
6
7
8
 /var/log/syslog
 clamsmtpd: 100001: accepted connection from: 127.0.0.1
 clamsmtpd: 100001: from=test@mytest.org, to=test@mytest.org, status=VIRUS:Eicar-Test-Signature
 clamd[22679]: /var/spool/clamsmtp/clamsmtpd.MYM8fU: Eicar-Test-Signature(81b9af91a0902e82aa217c215019d1b8:1055) FOUND
 clamd[22679]: /var/spool/clamsmtp/clamsmtpd.MYM8fU: Eicar-Test-Signature(81b9af91a0902e82aa217c215019d1b8:1055) FOUND

 /var/log/clamav/clamav.log
 Wed Jan 10 15:47:20 2018 -> /var/spool/clamsmtp/clamsmtpd.MYM8fU: Eicar-Test-Signature(81b9af91a0902e82aa217c215019d1b8:1055) FOUND

Spamassassin

Install these packages:

1
 apt-get install spamassassin spamc pyzor rblcheck razor

Edit the default file and enable spamassassin (using vmail user)

1
2
3
4
5
6
7
 vi /etc/default/spamassassin
 ENABLED=0
 OPTIONS="--create-prefs --max-children 5 --username vmail --helper-home-dir /home/vmail/ -s /var/log/spamassassin/spamd.log"
 PIDFILE="/var/run/spamd.pid"
 CRON=1

 systemctl enable spamassassin.service

Edit the configuration file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 vi  /etc/spamassassin/local.cf

 rewrite_header Subject *****SPAM*****
 report_safe             0
 required_score          5.0
 use_bayes               1
 use_bayes_rules         1
 bayes_auto_learn        1
 skip_rbl_checks         0
 use_razor2              1
 use_pyzor               1

 add_header all Status _YESNO_, score=_SCORE_ required=_REQD_ version=_VERSION_
 bayes_ignore_header X-Bogosity
 bayes_ignore_header X-Spam-Flag
 bayes_ignore_header X-Spam-Status

and modify these lines at the end of /etc/postfix/master.cf

1
2
3
4
5
6
 vi /etc/postfix/master.cf

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

Learn to spamassassin what is ham and spam in crontab every hour:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 cd /etc/cron.d
 vi sa-learn

 ### sa-learn run every hour
 # learn spam & sync
 10 */1 * * * root /usr/bin/sa-learn --spam /var/mail/vmail/*/*/.Junk/*/*
 # learn ham  & sync
 20 */1 * * * root  /usr/bin/sa-learn --ham /var/mail/vmail/*/*/cur/*

 chmod +x sa-learn

We can test it by sending an email with this Subject :

1
 XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

and, when it will be delivered, check the header:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on mail.mysite.org
 X-Spam-Flag: YES
 X-Spam-Level: **************************************************
 X-Spam-Report:
     * 1000 GTUBE BODY: Generic Test for Unsolicited Bulk Email
     * -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2)
     * [209.85.192.174 listed in wl.mailspike.net]
     * 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider
     * (test[at]testmail.com)
     * 0.0 HTML_MESSAGE BODY: HTML included in message
     * 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily
     * valid
     * -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's
     * domain
     * -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
     * 0.0 TVD_SPACE_RATIO No description available.
 X-Spam-Status: Yes, score=999.9 required=5.0 version=3.4.1

and the Subject of email will be changed in:

1
 *****SPAM***** XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

Sieve

Install this packages:

1
 apt-get install dovecot-sieve

and modify main.cf and master.cf:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  vi /etc/postfix/master.cf

 # Spamassassin
 spamassassin unix -     n       n       -       -       pipe
    flags=DROhu user=vmail:vmail argv=/usr/bin/spamc -f -e /usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop}

 vi /etc/postfix/main.cf

 #virtual_transport = virtual
 virtual_transport = spamassassin
 # Spamassassin move spam to junk folder
 spamassassin_destination_recipient_limit = 1

and these lines to dovecot.conf

 vi /etc/dovecot/dovecot.conf

 plugin {
   sieve = ~/.dovecot.sieve
   sieve_dir = ~/sieve
   sieve_after = /etc/dovecot/sieve/default.sieve
 }
 protocol lmtp {
   mail_plugins = $mail_plugins sieve
   postmaster_address = postmaster@mysite.org
 }

 protocol lda {
             mail_plugins = $mail_plugins sieve
 }

The last step is creating a sieve file with filters (in this case only for spam):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 mkdir /etc/dovecot/sieve/
 vi  /etc/dovecot/sieve/default.sieve

 require "fileinto";
 if header :contains "X-Spam-Flag" "YES" {
     fileinto "Junk";
 }

 chown vmail:vmail -R /etc/dovecot/sieve/
 systemctl restart postfix dovecot spamassassin

Final test

In order to test all features we send 3 emails to our new test mail (test@mytest.org) account from an external account or an internal one (mail@external.com) :

  • an email as fake spam - like the one sent above
  • an email with a fake virus as attachment - like the one sent above
  • a test email

The result of the test will be:

  • Spam detected and email moved to Junk folder:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 postfix/smtpd[5027]: connect from mail.external.com[1.1.1.1]
 postfix/smtpd[5027]: Anonymous TLS connection established from mail.external.com[1.1.1.1]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
 postgrey[23091]: action=pass, reason=client whitelist, client_name=mail.external.com, client_address=1.1.1.1 sender=mail@external.com, recipient=test@mytest.org
 postfix/smtpd[5027]: 90536FF946: client=mail.external.com[1.1.1.1]
 postfix/cleanup[5030]: 90536FF946: message-id=<CAP9h-e5Ji8MYtTjuj+UDVjXkVB56-yuNt8-oONFk8Khbp4xZUQ@mail.gmail.com>
 postfix/qmgr[4487]: 90536FF946: from=<mail@external.com>, size=3440, nrcpt=1 (queue active)
 clamsmtpd: 100055: accepted connection from: 127.0.0.1
 postfix/smtpd[5033]: connect from mail.mytest.org[127.0.0.1]
 postfix/smtpd[5033]: E6E9BFF947: client=mail.mytest.org[127.0.0.1], orig_queue_id=90536FF946, orig_client=mail-pf0-mail.external.com[1.1.1.1]
  postfix/cleanup[5030]: E6E9BFF947: message-id=<CAP9h-e5Ji8MYtTjuj+UDVjXkVB56-yuNt8-oONFk8Khbp4xZUQ@mail.external.com>
 postfix/qmgr[4487]: E6E9BFF947: from=<mail@external.com>, size=3654, nrcpt=1 (queue active)
 clamsmtpd: 100055: from=mail@external.com, to=test@mytest.org, status=CLEAN
 postfix/smtp[5031]: 90536FF946: to=<test@mytest.org>, relay=127.0.0.1[127.0.0.1]:10026, delay=0.96, delays=0.83/0/0.04/0.08, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as E6E9BFF947)
 postfix/qmgr[4487]: 90536FF946: removed
 postfix/smtpd[5033]: disconnect from mail.mytest.org[127.0.0.1] ehlo=1 xforward=2 mail=1 rcpt=1 data=1 quit=1 commands=7
 postfix/smtpd[5027]: disconnect from mail.external.com[1.1.1.1] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
 dovecot: lda(test@mytest.org): sieve: msgid=<CAP9h-e5Ji8MYtTjuj+UDVjXkVB56-yuNt8-oONFk8Khbp4xZUQ@mail.external.com>: stored mail into mailbox 'Junk'
 postfix/pipe[5035]: E6E9BFF947: to=<test@mytest.org>, relay=spamassassin, delay=1.7, delays=0.08/0/0/1.6, dsn=2.0.0, status=sent (delivered via spamassassin service)
 postfix/qmgr[4487]: E6E9BFF947: removed
  • Virus detected and email deleted:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 postfix/smtpd[5027]: connect from mail.external.com[1.1.1.1]
 postfix/smtpd[5027]: Anonymous TLS connection established from mail.external.com[1.1.1.1]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
 postgrey[23091]: action=pass, reason=client whitelist, client_name=mail.external.com, client_address=1.1.1.1, sender=mail@external.com, recipient=test@mytest.org
 postfix/smtpd[5027]: 0828BFF946: client=mail.external.com[1.1.1.1]
 postfix/cleanup[5030]: 0828BFF946: message-id=<CAP9h-e5UY=36_76SEfa5EaN4eNHsLNxceeFCS71wCTE549CEhg@mail.external.com>
 postfix/qmgr[4487]: 0828BFF946: from=<mail@external.com>, size=3051, nrcpt=1 (queue active)
 clamsmtpd: 100054: accepted connection from: 127.0.0.1
 postfix/smtpd[5033]: connect from mail.mytest.org[127.0.0.1]
 postfix/smtpd[5033]: 67254FF947: client=mail.mytest.org[127.0.0.1], orig_queue_id=0828BFF946, orig_client=mail.external.com[1.1.1.1]
 clamsmtpd: 100054: quarantined virus file as: /var/spool/clamsmtp/virus.niyiVU
 clamd[8617]: /var/spool/clamsmtp/clamsmtpd.GTT2GB: Eicar-Test-Signature(04c2f0713d8d1f9e8630e322b6e54360:3051) FOUND
 clamd[8617]: /var/spool/clamsmtp/clamsmtpd.GTT2GB: Eicar-Test-Signature(04c2f0713d8d1f9e8630e322b6e54360:3051) FOUND
 postfix/smtp[5031]: 0828BFF946: to=<test@mytest.org>, relay=127.0.0.1[127.0.0.1]:10026, delay=0.79, delays=0.74/0/0.04/0.01, dsn=2.0.0, status=sent (250 Virus Detected; Discarded Email)
 postfix/qmgr[4487]: 0828BFF946: removed
 clamsmtpd: 100054: from=mail@external.com, to=test@mytest.org, status=VIRUS:Eicar-Test-Signature
 postfix/smtpd[5033]: disconnect from mail.mytest.org[127.0.0.1] ehlo=1 xforward=2 mail=1 rcpt=1 rset=1 quit=1 commands=7
 postfix/smtpd[5027]: disconnect from mail.external.com[1.1.1.1]] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
  • Email delivered to Inbox folder:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 postfix/smtpd[5027]: connect from mail.external.com[1.1.1.1]
 postfix/smtpd[5027]: Anonymous TLS connection established from mail.external.com[1.1.1.1]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
 postgrey[23091]: action=pass, reason=client whitelist, client_name=mail.external.com, client_address=1.1.1.1, sender=mail@external.com, recipient=test@mytest.org
 postfix/smtpd[5027]: BD1F0FF94A: client=mail.external.com[1.1.1.1]
 postfix/cleanup[5092]: BD1F0FF94A: message-id=<CAP9h-e57=m8d1YteBUAWfsA4yFt_6+BdAhWceK_-iMF8jrxRpQ@mail.external.com>
 postfix/qmgr[4487]: BD1F0FF94A: from=<mail@external.com>, size=2691, nrcpt=1 (queue active)
 clamsmtpd: 100057: accepted connection from: 127.0.0.1
 postfix/smtpd[5096]: connect from mail.mytest.org[127.0.0.1]
 postfix/smtpd[5096]: 2DC9CFF94B: client=mail.mytest.org[127.0.0.1], orig_queue_id=BD1F0FF94A, orig_client=mail.external.com[1.1.1.1]
 postfix/cleanup[5092]: 2DC9CFF94B: message-id=<CAP9h-e57=m8d1YteBUAWfsA4yFt_6+BdAhWceK_-iMF8jrxRpQ@mail.external.com>
 postfix/qmgr[4487]: 2DC9CFF94B: from=<mail@external.com>, size=2905, nrcpt=1 (queue active)
 clamsmtpd: 100057: from=mail@external.com, to=test@mytest.org, status=CLEAN
 postfix/smtp[5094]: BD1F0FF94A: to=<test@mytest.org>, relay=127.0.0.1[127.0.0.1]:10026, delay=0.99, delays=0.82/0.01/0.05/0.11, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 2DC9CFF94B)
 postfix/qmgr[4487]: BD1F0FF94A: removed
 postfix/smtpd[5096]: disconnect from mail.mytest.org[127.0.0.1] ehlo=1 xforward=2 mail=1 rcpt=1 data=1 quit=1 commands=7
 postfix/smtpd[5027]: disconnect from mail.external.com[1.1.1.1] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
 dovecot: lda(test@mytest.org): sieve: msgid=<CAP9h-e57=m8d1YteBUAWfsA4yFt_6+BdAhWceK_-iMF8jrxRpQ@mail.external.com>: stored mail into mailbox 'INBOX'
 postfix/pipe[5098]: 2DC9CFF94B: to=<test@mytest.org>, relay=spamassassin, delay=1.7, delays=0.1/0.01/0/1.6, dsn=2.0.0, status=sent (delivered via spamassassin service)
 postfix/qmgr[4487]: 2DC9CFF94B: removed

Roundcube

Download the latest roundcube release at https://roundcube.net/ and put it on /var/www :

1
 mv /var/www/roundcube-etc-etc /var/www/roundcube

Create a new user/db for roundcube:

1
2
3
4
 mysql -u root -p
    CREATE USER 'roundcube'@'localhost' IDENTIFIED BY 'choose_a_password';
    CREATE DATABASE roundcubemail /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
    GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost IDENTIFIED BY 'choose_a_password';

and populate it:

1
2
 cd /var/www/roundcube
 mysql roundcubemail < SQL/mysql.initial.sql

Follow the instruction at http://www.mysite.org/installer and, after installation steps are finished, modify the config file on SMTP parameters:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 rm -rf installer/
 cd /var/www/cube/config
 vi config.inc.php

 // ----------------------------------
 // SMTP
 // ----------------------------------
 $config['smtp_debug'] = true;
 $config['smtp_server'] = 'tls://mail.mysite.org';
 $config['smtp_port'] = 587;
 $config['smtp_user'] = '%u';
 $config['smtp_pass'] = '%p';
 $config['smtp_auth_type'] = 'PLAIN';
 $config['smtp_auth_cid'] = null;
 $config['smtp_auth_pw'] = null;
 $config['smtp_helo_host'] = '';
 $config['smtp_timeout'] = 0;
 $config['smtp_conn_options'] = array(
    'ssl'         => array(
      'verify_peer'  => false,
      'verify_depth' => 3,
      'cafile'       => '/etc/letsencrypt/live/mail.mysite.org/cert.pem',
    ),
  );