Install and configure Postfix and Dovecot
Updated on
•6 min read

This is the second post of our Setting up and configuring a mail server series. In this post we will show you how to install and configure Postfix and Dovecot, the two main components of our mail system.
Postfix is an open-source mail transfer agent (MTA), a service used to send and receive emails. Dovecot is an IMAP/POP3 server and in our setup it will also handle local delivery and user authentication.
This tutorial was written for Ubuntu 16.04, however the same steps with small modifications should work on any newer version of Ubuntu .
Prerequisites
Before continuing with this tutorial, make sure you are logged in as a user with sudo privileges .
Install Postfix and Dovecot
Dovecot packages in the Ubuntu default repositories are outdated. In order to take advantage of the imap_sieve
module we will install Dovecot from the Dovecot community repository.
Add the repository GPG key to your apt sources keyring with the following wget command :
wget -O- https://repo.dovecot.org/DOVECOT-REPO-GPG | sudo apt-key add -
Enable the Dovecot community repository using the following command:
echo "deb https://repo.dovecot.org/ce-2.3-latest/ubuntu/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee -a /etc/apt/sources.list.d/dovecot.list
sudo apt update
sudo debconf-set-selections <<< "postfix postfix/mailname string $(hostname -f)"
sudo debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'"
sudo apt install postfix postfix-mysql dovecot-imapd dovecot-lmtpd dovecot-pop3d dovecot-mysql
Postfix Configuration
We will setup Postfix to use virtual mailboxes and domains.
Start by creating the sql
configuration files which will instruct postfix how to access the MySQL database
, created in the first part of this series
.
sudo mkdir -p /etc/postfix/sql
Open your text editor and create the following files:
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
user = postfixadmin
password = P4ssvv0rD
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
Once the SQL configuration files are created, update the main postfix configuration file to include information about the virtual domains, users, and aliases which are stored in the MySQL database .
sudo postconf -e "virtual_mailbox_domains = mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf"
sudo postconf -e "virtual_alias_maps = mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf, mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf"
sudo postconf -e "virtual_mailbox_maps = mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf, mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf"
The local delivery agent will deliver the incoming emails to the users’ mailboxes. Run the following command to set Dovecot’s LMTP service as a default mail delivery transport:
sudo postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
Set the TL parameters using the previously generated Let’s encrypt SSL certificate:
sudo postconf -e 'smtp_tls_security_level = may'
sudo postconf -e 'smtpd_tls_security_level = may'
sudo postconf -e 'smtp_tls_note_starttls_offer = yes'
sudo postconf -e 'smtpd_tls_loglevel = 1'
sudo postconf -e 'smtpd_tls_received_header = yes'
sudo postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/mail.linuxize.com/fullchain.pem'
sudo postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/mail.linuxize.com/privkey.pem'
Configure the authenticated SMTP settings and hand off authentication to Dovecot:
sudo postconf -e 'smtpd_sasl_type = dovecot'
sudo postconf -e 'smtpd_sasl_path = private/auth'
sudo postconf -e 'smtpd_sasl_local_domain ='
sudo postconf -e 'smtpd_sasl_security_options = noanonymous'
sudo postconf -e 'broken_sasl_auth_clients = yes'
sudo postconf -e 'smtpd_sasl_auth_enable = yes'
sudo postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination'
We’ll also need to edit the Postfix master configuration file master.cf
and enable the submission port (587
) and smtps port (465
).
Open the file with your text editor and uncomment/edit the following lines:
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
Restart the postfix service for changes to take effect.
sudo systemctl restart postfix
At this point you have successfully configured the Postfix service.
Configure Dovecot
In this section, we’ll configure Dovecot to match our setup. Make sure you edit the lines highlighted in yellow.
Start by configuring the dovecot-sql.conf.ext
file that instructs Dovecot how to access the database and how to find the information about email accounts.
driver = mysql
connect = host=127.0.0.1 dbname=postfixadmin user=postfixadmin password=P4ssvv0rD
default_pass_scheme = MD5-CRYPT
iterate_query = SELECT username AS user FROM mailbox
user_query = SELECT CONCAT('/var/mail/vmail/',maildir) AS home, \
CONCAT('maildir:/var/mail/vmail/',maildir) AS mail, \
5000 AS uid, 5000 AS gid, CONCAT('*:bytes=',quota) AS quota_rule \
FROM mailbox WHERE username = '%u' AND active = 1
password_query = SELECT username AS user,password FROM mailbox \
WHERE username = '%u' AND active='1'
Do not forget to use the correct MySQL credentials (dbname, user and password).
Next, edit the conf.d/10-mail.conf
file and edit the following variables:
...
mail_location = maildir:/var/mail/vmail/%d/%n
...
mail_uid = vmail
mail_gid = vmail
...
first_valid_uid = 5000
last_valid_uid = 5000
...
mail_privileged_group = vmail
...
mail_plugins = quota
...
To make the authentication work, open the conf.d/10-auth.conf
, edit the following lines and include the auth-sql.conf.ext
file:
...
disable_plaintext_auth = yes
...
auth_mechanisms = plain login
...
#!include auth-system.conf.ext
!include auth-sql.conf.ext
...
Open the conf.d/10-master.conf
file, and modify it as follows:
...
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
...
}
...
service auth {
...
unix_listener auth-userdb {
mode = 0600
user = vmail
group = vmail
}
...
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
...
}
...
service auth-worker {
user = vmail
}
...
service dict {
unix_listener dict {
mode = 0660
user = vmail
group = vmail
}
}
...
Open the conf.d/10-ssl.conf
and enable SSL/TLS.
...
ssl = yes
...
ssl_cert = </etc/letsencrypt/live/mail.linuxize.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.linuxize.com/privkey.pem
ssl_dh = </etc/ssl/certs/dhparam.pem
...
ssl_cipher_list = EECDH+AES:EDH+AES+aRSA
...
ssl_prefer_server_ciphers = yes
...
If you have followed this series from the beginning, you should already have the
fullchain.pem
, privkey.pem
, dhparam.pem
files created on your server. For more information about how to create a free Let’s encrypt SSL certificate and Diffie–Hellman key check this tutorial
.Thanks to Nevyn for noticing the problem and providing a solution.
Open the conf.d/20-imap.conf
file and activate the imap_quota
plugin:
...
protocol imap {
...
mail_plugins = $mail_plugins imap_quota
...
}
...
Open the conf.d/20-lmtp.conf
file and edit it as follows:
...
protocol lmtp {
postmaster_address = [email protected]
mail_plugins = $mail_plugins
}
...
Define the default Mailboxes in the conf.d/15-mailboxes.conf
file:
...
mailbox Drafts {
special_use = \Drafts
}
mailbox Spam {
special_use = \Junk
auto = subscribe
}
mailbox Junk {
special_use = \Junk
}
...
There are two different types of quota sizes, one is set for the entire domain and the other per user mailbox. In the previous part of this series we have already enabled the quota support in PostfixAdmin which means the quota information will be stored in the PostfixAdmin database.
Now we need to configure Dovecot to connect to the database, to handle quota limits and to run a script that sends a mail to the user when user’s quota exceeds a specified limit. To do so open the conf.d/90-quota.conf
file and modify it as follows:
plugin {
quota = dict:User quota::proxy::sqlquota
quota_rule = *:storage=5GB
quota_rule2 = Trash:storage=+100M
quota_grace = 10%%
quota_exceeded_message = Quota exceeded, please contact your system administrator.
quota_warning = storage=100%% quota-warning 100 %u
quota_warning2 = storage=95%% quota-warning 95 %u
quota_warning3 = storage=90%% quota-warning 90 %u
quota_warning4 = storage=85%% quota-warning 85 %u
}
service quota-warning {
executable = script /usr/local/bin/quota-warning.sh
user = vmail
unix_listener quota-warning {
group = vmail
mode = 0660
user = vmail
}
}
dict {
sqlquota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext
}
We also need to tell dovecot how to access the quota SQL dictionary. Open the dovecot-dict-sql.conf.ext
file and edit the following lines:
...
connect = host=127.0.0.1 dbname=postfixadmin user=postfixadmin password=P4ssvv0rD
...
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
...
# map {
# pattern = shared/expire/$user/$mailbox
# table = expires
# value_field = expire_stamp
#
# fields {
# username = $user
# mailbox = $mailbox
# }
# }
...
Create the following shell script which will send an email to the user if its quota exceeds a specified limit:
#!/bin/sh
PERCENT=$1
USER=$2
cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=dict:User quota::noenforcing:proxy::sqlquota"
From: [email protected]
Subject: Quota warning
Your mailbox is now $PERCENT% full.
EOF
Make the script executable by running the following chmod
command:
sudo chmod +x /usr/local/bin/quota-warning.sh
Finally restart the dovecot service for changes to take effect.
sudo systemctl restart dovecot
Conclusion
By now you should have a fully functional mail system. In the next part of this series, we will show you how to install and integrate Rspamd .
This post is a part of the Setting up and configuring a mail server series.
Other posts in this series: