Mail server setup (Postfix, Dovecot, MySQL, SpamAssasin)

Mail server setup (Postfix, Dovecot, MySQL, SpamAssasin)


A “short” guide on Mail server setup.  We’re going to rely on Postfix, Dovecot, MySQL and anti-spam including some details related to OpenDKIM/SPF/ReversePTR.

Install Packages For Mail Server Setup

First of all, we need to install required packages as a first step in mail server setup.


In postfix configuration, select Internet Site.

Create a MySQL Database, Virtual Domains, Users and Aliases

We’re going to create a MiSQL DB, containing 3 different tables:

  • Domains
  • Users
  • Aliases

Login to MySQL and create servermail database:

mysql -u root -p

First create a new user, specific for mail authentication:


Use that DB to create tables and data:

mysql> USE servermail;

Create domains tables for domains recognized as authorized domains:

CREATE TABLE `virtual_domains` (
`name` VARCHAR(50) NOT NULL,

User table, for email addresses and passwords, associating each user with a domain:

CREATE TABLE `virtual_users` (
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
UNIQUE KEY `email` (`email`),

Aliases table, for specifying emails that are going to be forward to another email:

CREATE TABLE `virtual_aliases` (
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,

With structure set, moving to data segment.

Virtual Domains

Insert domain(s):

INSERT INTO `servermail`.`virtual_domains`
(`id` ,`name`)
('1', ''),
('2', '');

Virtual Emails

Create email address and passwords for each domain:

INSERT INTO `servermail`.`virtual_users`

Virtual Aliases

Create alias that we are going to forward to some other emal address (destination):

INSERT INTO `servermail`.`virtual_aliases`

EncFS (optional)

As you can see  in the picture above (a warning while installing), EncFS is not the ideal one. It has some known vulnerabilities, so maybe some other alternatives like CryFS  might be better idea. For this example, we’ll stick to EncFS.

$ apt-get install encfs
mkdir /encrypted-mail /decrypted-mail
chgrp mail /decrypted-mail/
chmod -R g+rw /decrypted-mail/
gpasswd -a mail fuse
Creating new encrypted volume.
Please choose from one of the following options:
 enter "x" for expert configuration mode,
 enter "p" for pre-configured paranoia mode,
 anything else, or an empty line will select standard mode.
?> p
Paranoia configuration selected.
Configuration finished.  The filesystem to be created has
the following properties:
Key Size: 256 bits
Block Size: 1024 bytes, including 8 byte MAC header
Each file contains 8 byte header with unique IV data.
Filenames encoded using IV chaining mode.
File data IV is chained to filename IV.
File holes passed through to ciphertext.
The external initialization-vector chaining option has been
enabled.  This option disables the use of hard links on the
filesystem. Without hard links, some programs may not work.
more information, please see the encfs mailing list.
If you would like to choose another configuration setting,
please press CTRL-C now to abort and start over.
Now you will need to enter a password for your filesystem.
You will need to remember this password, as there is absolutely
no recovery mechanism.  However, the password can be changed
later using encfsctl.
New Encfs Password:
Verify Encfs Password:


Configure Postfix

What is Postfix? It is Wietse Venema’s mail server (an “MTA” in the email lingo), that started life at IBM research as an alternative to the widely-used Sendmail program. Essentially it runs SMTP, and delivers incoming mail to Dovecot. As a next step in mail server setup, we are going to configure Postfix to handle the SMTP connections and messages for each user introduced in the MySQL Database.

Just in case, create backup(s) for the config files we’re going to change. Open the file to modify it:

nano /etc/postfix/

First we need to comment the TLS Parameters and append other parameters. You can use the Free SSL certificates and the paths that are suggested:

# TLS parameters
#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

or you could modify depending on your personal configuration, for instance using Let’s encrypt.

# TLS parameters


smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions =


#mydestination =,,, localhost
mydestination = localhost

Verify that myhostname parameter is set with your FQDN.

myhostname =


virtual_transport = lmtp:unix:private/dovecot-lmtp


virtual_mailbox_domains = mysql:/etc/postfix/
virtual_mailbox_maps = mysql:/etc/postfix/
virtual_alias_maps = mysql:/etc/postfix/


First we need to create the file. It’s necessary to change the values depending your personal configuration.

nano /etc/postfix/
user = usermail
password = mailpassword
hosts =
dbname = servermail

Then we need to restart Postfix.

service postfix restart

We need to ensure that Postfix finds your domain, so we need to test it with the following command. If successful, it should return 1:

postmap -q mysql:/etc/postfix/

Then we need to create the file.

nano /etc/postfix/ 
user = usermail
password = mailpassword
hosts =
dbname = servermail

Restart Postfix again:

service postfix restart


postmap -q mysql:/etc/postfix/


nano /etc/postfix/
user = usermail
password = mailpassword
hosts =
dbname = servermail

Restart Postfix again:

service postfix restart

We need to verify that Postfix can find your aliases. Enter the following command and it should return the mail that’s forwarded to the alias:

postmap -q mysql:/etc/postfix/


nano /etc/postfix/

We need to uncomment these lines and append other parameters:

submission inet n       -       -       -       -       smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject


service postfix restart

Note: You can use “netstat -tulpn” cmd to check if your system listens on specific ports, or you can use this tool to scan your domain ports and verify that port 25 and 587 are open.

Configure Dovecot

Dovecot, an “LDA” (Local Delivery Agent) in the email lingo,  is an open source IMAP and POP3 email server for Linux/UNIX-like systems, written with security in mind. Essentially it runs IMAP.

Backup 7 files that are about to be modified, so that you could revert it to default if you needed to:


Edit configuration file from Dovecot.

nano /etc/dovecot/dovecot.conf

Verify this option is uncommented.

!include conf.d/*.conf


protocols = imap lmtp

Then we are going to edit the mail configuration file:

nano /etc/dovecot/conf.d/10-mail.conf




mail_privileged_group = mail

Ensure permissions are 775 like this:

>drwxrwsr-x 3 root vmail 4096 Jan 24 21:23 /var/mail


mkdir -p /var/mail/vhosts/

Create a vmail user and group with an id of 5000

groupadd -g 5000 vmail 


chown -R vmail:vmail /var/mail


nano /etc/dovecot/conf.d/10-auth.conf

Uncomment and/or set following lines:

disable_plaintext_auth = yes
auth_mechanisms = plain login
#!include auth-system.conf.ext


nano /etc/dovecot/conf.d/auth-sql.conf.ext

Enter following code:

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
userdb {
  driver = static


nano /etc/dovecot/dovecot-sql.conf.ext

Uncomment the driver parameter and set mysql as parameter:

driver = mysql
default_pass_scheme = SHA512-CRYPT


chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot


nano /etc/dovecot/conf.d/10-master.conf

##Uncomment inet_listener_imap and modify to port 0
service imap-login {
  inet_listener imap {
    port = 0

#Create LMTP socket and this configurations
service lmtp {
	   mode = 0600
	   user = postfix
	   group = postfix
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port =

Modify unix_listener parameter to service_auth like this:

service auth {

  unix_listener /var/spool/postfix/private/auth {
  mode = 0666
  user = postfix
  group = postfix

  unix_listener auth-userdb {
  mode = 0600
  user = vmail
  #group =

  # mode = 0666

  user = dovecot

Also modify service auth-worker like this:

service auth-worker {
  # $default_internal_user.
  user = vmail


# nano /etc/dovecot/conf.d/10-ssl.conf

ssl = required

ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem

or as we mentioned earlier, set Let’s encrypt keys:

ssl_cert = </etc/letsencrypt/live/<>/fullchain.pem
ssl_key = </etc/letsencrypt/live/<>/privkey.pem

Generating SSL certs:



Furthermore, you should check that port 993 is open and working (in case you enable pop3; you should check also port 995).

telnet 993


- Username:
- Password: email1's password


Avoiding SPAM filters (SPF, DKIM, DMARC)

We’re going to setup SPF, DKIM, DMARC and (maybe) PTR. Due to the size of this post/tutorial, we’re going to move these to individual posts:

SPF Setup

Check SPF Postfix Setup.

DKIM Setup

Check OpenDKIM Postfix Setup.


Check DMARC Postfix Setup.

Reverse PTR

The Reverse DNS is one of the basic requirements for running some Internet protocols. It is also often used as a spam filter to determine whether the IP address of the incoming message matches an authenticated domain name and to block the message if it doesn’t.


Spam can be annoying and dangerous, so its always a good idea to set some anti-spam services. We’ll include few: dspam and SpamAssasin.  Postfix domain block is also usefull at times.

Postfix Block Domains

To block Emails to/from specific domains, start by creating the access list file (e.g. /etc/postfix/access):

$ nano /etc/postfix/access

In there, add domain names followed by the action (DISCARD or REJECT). We recommend DISCARD: DISCARD REJECT

Tell postfix to use that file. Edit and add/update smtpd_sender_restrictions header:

$ nano /etc/postfix/
smtpd_sender_restrictions = check_sender_access hash:/etc/postfix/access

After you finish, postmat the file to prepare postfix to use it (every time you modify the file).

$ postmap /etc/postfix/access

Restart Postfix.



patch these in /etc/dspam/dspam.conf:

Home /decrypted-mail/dspam
TrustedDeliveryAgent "/usr/sbin/sendmail"
Tokenizer osb
IgnoreHeader X-Spam-Status
IgnoreHeader X-Spam-Scanned
IgnoreHeader X-Virus-Scanner-Result
IgnoreHeader X-Virus-Scanned
IgnoreHeader X-DKIM
IgnoreHeader DKIM-Signature
IgnoreHeader DomainKey-Signature
IgnoreHeader X-Google-Dkim-Signature
ParseToHeaders on
ChangeModeOnParse off
ChangeUserOnParse full
ServerPID               /var/run/dspam/
ServerDomainSocketPath  "/var/run/dspam/dspam.sock"
ClientHost      /var/run/dspam/dspam.sock

Create the directory:

mkdir /decrypted-mail/dspam
chown dspam:dspam /decrypted-mail/dspam


signatureLocation=headers  # { message | headers } -> default:message

Edit /etc/postfix/

dspam     unix  -       n       n       -       10      pipe
dovecot   unix  -       n       n       -       -       pipe


nano /etc/postfix/dspam_filter_access
/./   FILTER dspam:unix:/run/dspam/dspam.sock

Patch the end of /etc/postfix/

# new settings for dspam
dspam_destination_recipient_limit = 1 #only scan one mail at a time
smtpd_client_restrictions =
   permit_sasl_authenticated #localhost doesn't get scanned

Integrating dspam with imap:

nano /etc/dovecot/conf.d/20-imap.conf
mail_plugins = $mail_plugins antispam

Integrating dspam with lmtp:

protocol lmtp {
mail_plugins = $mail_plugins sieve

Telling sieve to move spam into a Spam folder. Edit /decrypted-mail/ (e.g. for your username and domain):

  # Mark as read
  setflag "\\Seen";
  # Move into the Junk folder
  fileinto "Spam";
  # Stop processing here


plugin {
   # Antispam (DSPAM)
   antispam_backend = dspam
   antispam_allow_append_to_spam = YES
   antispam_spam = Spam;Junk
   antispam_trash = trash;Trash
   antispam_signature = X-DSPAM-Signature
   antispam_signature_missing = error
   antispam_dspam_binary = /usr/bin/dspam
   antispam_dspam_spam = --class=spam
   antispam_dspam_notspam = --class=innocent
   antispam_dspam_result_header = X-DSPAM-Result

Give postfix and dovecot a kick:

service postfix restart
service dovecot restart

Incoming messages should have headers like:

X-Dspam-Result: Innocent
X-Dspam-Confidence: 0.9899
X-Dspam-Probability: 0.0000
X-Dspam-Signature: 51b9246071121935811689
X-Dspam-Factors: 27, Received*12+Jun, 0.01000, Received*12+Jun, 0.01000, Received*Postfix+with, 0.01000, Received*with+#+id, 0.01000, Received*, 0.01000, Content-Type*text+plain, 0.01000, Received*Postfix+#+ESMTP, 0.01000, Received*, 0.01000, Received*drew+#+#+#+Jun, 0.01000, Received*Wed+#+Jun, 0.01000, Received*Wed+#+Jun, 0.01000, Received*, 0.01000, Received*Wed+#+#+2013, 0.01000, Received*Wed+#+#+2013, 0.01000, Received*Postfix+#+#+id, 0.01000, Received*, 0.01000, Received*ESMTP+id, 0.01000, Date*12+Jun, 0.01000, Received*for+#+#+#+12, 0.01000, Date*Jun+2013, 0.01000, Received*by+#+Postfix, 0.01000, Received*by+#+with, 0.01000, Received*, 0.01000, Received*by+#+#+#+ESMTP, 0.01000, Date*Wed+#+#+2013, 0.01000, Received*drew+#+#+12, 0.01000, Received*, 0.01000


First we need to install SpamAssassin.

apt-get install spamassassin spamc

Then we also need to create a user for SpamAssassin.

adduser spamd --disabled-login

To successfully configure SpamAssassin, it’s necessary to open and modify the configuration settings.

nano /etc/default/spamassassin

Also, we need to change the ENABLED parameter to enable SpamAssassin daemon.


We need to configure the home and options parameters.


Then we need to specify the PID_File parameter like this:


Finally, we need to specify that SpamAssassin’s rules will be updated automatically.


We need to open /etc/spamassassin/ to set up the anti-spam rules. SpamAssassin will score each mail and if it determines this email is greater than 5.0 on its spam check, then it automatically will be considered spam. You could use the following parameters to configure the anti-spam rules:

nano /etc/spamassassin/

report_safe             0
required_score          5.0
use_bayes               1
use_bayes_rules         1
bayes_auto_learn        1
skip_rbl_checks         0
use_razor2              0
use_dcc                 0
use_pyzor               0


nano /etc/postfix/

smtp      inet  n       -       -       -       -       smtpd
-o content_filter=spamassassin

Finally, it is finished. We need to append the following parameters:

spamassassin unix -     n       n       -       -       pipe

It is also necessary to start SpamAssassin and restart Postfix to begin verifying spam from emails.

service spamassassin start
service postfix restart

Done! Mail server with Postfix and Dovecot with MySQL authentication and spam filtering with either dpan or SpamAssassin is ready!

Things to work on:

  • Full-text search: relying on Java, solr-tomcat & dovecot-solr
  • Webmail: check next tutorial related to simple webmail control (Rainloop).
  • Requiring TLS encryption: makes you non-RFC-compliant, but makse NSA life a bit more difficult
  • Greylisting: This is a cool idea involving providing a “temporary failure” each time a new sender sends a message. Legitimate senders will keep retrying, and after a few minutes you add them to a “good” list. Spammers will give up, and furthermore, their mail messages will never even hit disk. It’s actually really easy configure, just apt-get install postgrey and then add check_policy_service inet: under smtpd_client_restrictions in /etc/postfix/