How to Setup Mail Server Using Postfix, MariaDB, Dovecot and Roundcube

Hello everybody, today we are going to set up a mail server using Postfix, Devcot and MariaDB on Ubuntu 16.04 LTS.

Here we setup Postfix (smtp server), Dovecot (imap/pop server) and MariaDB to store information on virtual domains and users.

The task of the smtp server is to accept incoming mails and relay outgoing mails from authorized users on the system. Whereas Dovecot allows authorized users to access their Inbox and read whatever mails there are. So, our primary focus in the article is to set up a fast and secure mail server using virtual users.

Setup Prerequisites

There are a number of prerequisites, that should be followed before moving towards mail server setup. This includes domain forwarding to your server and setup a static IP address to your server. Open this file '/etc/hostname' to setup your appropriate hostname.

# vim /etc/hosts ubuntu-16

In order to use your mail server on a wider network, you must correctly configure the DNS and MX records for your host's domain. Then make sure that the iptables firewall or any other external firewall is not blocking any of the standard mail ports on your server that is (25, 465, 587, 110, 995, 143, and 993).

After domain and hostname setup, run below command to update your system with latest updates before installing its other required packages.

# apt-get update

Installing Packages

Now install all required packages including 'Postfix', 'Devcot' and 'MySQL' with some other necessary packages to setup our mail server by flowing the command below using root user credentials.

# aptitude update && aptitude install apache2 postfix dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql spamassassin clamav clamav-daemon clamav-base mariadb-client mariadb-server php

Once you pressed 'y' key to continue, you will be prompted to configure postfix configurations. Choose 'Internet Site' under postfix configuration and click on the 'ok' key to continue.

Postfix Configurations

Next, you will be asked to type your system mail name which will be included in your emails.

system mail name

After you click on the 'Ok' button, your system will process for a while to complete the installation of all packages.

Setup MariaDB Database

When the installation is complete and the above service are enabled and running, we will start off by setting up the database and tables to store information about Postfix mail accounts.

Run the below command to configure root passowrd on your MariaDB.

# mysql_secure_installation
Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
... Success!

Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
- Dropping test database...
ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist
... Failed! Not critical, keep moving...
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
... Success!

Cleaning up...

All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

Now connect to the MariDB and run below commands to create a new database and the MySQL user and grant the new user permissions over the newly created database.

# mysql -u root -p
MariaDB [(none)]> create database mailserver;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> GRANT SELECT ON mailserver.* TO 'mailuser'@'' IDENTIFIED BY '*****';
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Now we will create some tables using the following commands. First run below command for the domains that will receive mail on our domain.

CREATE TABLE `virtual_domains` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,

To create a new tables for all of your email addresses and passwords use below query .

CREATE TABLE `virtual_users` (
`id` int(11) NOT NULL auto_increment,
`domain_id` int(11) NOT NULL,
`password` varchar(106) NOT NULL,
`email` varchar(100) NOT NULL,
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE

Then create one more table for the email aliases using below query.

CREATE TABLE `virtual_aliases` (
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE

creating tables in MariaDB

We have created a database and some necessary tables, now will add some data to MySQL by adding some test domains to the virtual_domains table by using the following query.

INSERT INTO `mailserver`.`virtual_domains`
(`id` ,`name`)
('1', ''),
('2', ''),
('3', 'ubuntu-16'),
('4', '');

Then add email addresses to the virtual_users table by replace the email address values with the addresses that you wish to configure on the mailserver and update the password values with strong passwords you have.

INSERT INTO `mailserver`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
('1', '1', ENCRYPT('password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), ''),
('2', '1', ENCRYPT('password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '');

Run the following query to insert the data into the tables for email alias setup.

INSERT INTO `mailserver`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
('1', '1', '', '');

inserting db data

Testing MariaDB Data

After entering all the required information into MariaDB, check that the data is there.

Let's run below query to check the contents of the virtual_domains table first.

MariaDB [mailserver]> SELECT * FROM mailserver.virtual_domains;
| id | name |
| 1 | |
| 2 | |
| 3 | ubuntu-16 |
| 4 | |
4 rows in set (0.00 sec)

Check the 'virtual_users' and 'virtual_aliases' table to verify the the hashed passwords should be there using below queries as shown.

MariaDB [mailserver]> SELECT * FROM mailserver.virtual_users;
| id | domain_id | password | email |
| 1 | 1 | $6$b4046061316dbf73$eth.RbLdk2Z1ArUti2yYzoF0T8/xz1wbVrrX1RticBNTeKz4wWKj23zj49UOSW95njitEWv65tlketGVvzRz01 | |
| 2 | 1 | $6$a193a0a79bd30c14$RN1HiqeeuwJ2uvjY43VO0vLLj2GFpJpPtOu3rCZH66qVWIlFUcRDg/7gr9cpVuyYSGejXoF7D69YgI/vQPR17. | |
2 rows in set (0.00 sec)
MariaDB [mailserver]> SELECT * FROM mailserver.virtual_aliases;
| id | domain_id | source | destination |
| 1 | 1 | | |
1 row in set (0.00 sec)

Setup Postfix Configurations

After MySQL database setup, now we will setup Postfix so the server can accept incoming messages for the domains. Create a copy of the default Postfix configuration file in case you need to revert to the default configuration.

# cp /etc/postfix/ /etc/postfix/

Then open the file using vi or vim editor to match the following configuration but do not forget to update your domain and hostname.

# vi /etc/postfix/
# See /usr/share/postfix/ for a commented, more complete version

# Debian specific: Specifying a file name will cause the first
# line of that file to be used as the name. The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# 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

#Enabling SMTP for authenticated users, and handing off authentication to Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

smtpd_recipient_restrictions =

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname =
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
#mydestination =,,, localhost
mydestination = localhost
relayhost =
mynetworks = [::ffff:]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

#Handing off local delivery to Dovecot's LMTP, and telling it where to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp

#Virtual domains, users, and aliases
virtual_mailbox_domains = mysql:/etc/postfix/
virtual_mailbox_maps = mysql:/etc/postfix/
virtual_alias_maps = mysql:/etc/postfix/,

Close the file after making saved changes and then create a new file for your virtual domains and ensure that you update these changes according to your own setup.

#vim /etc/postfix/
user = mailuser
password = mailuser_pass
hosts =
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'

Create below file and put the follwoing contents in it with you password.

# vim /etc/postfix/
user = mailuser
password = mailuser_pass
hosts =
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'

Save and close the file and now create new file '/etc/postfix/' and enter the following values as shown.

# vi /etc/postfix/
user = mailuser
password = mailuser_pass
hosts =
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'

Then create '/etc/postfix/' file and enter the following values.

# vi /etc/postfix/
user = mailuser
password = mailuser_pass
hosts =
dbname = mailserver
query = SELECT email FROM virtual_users WHERE email='%s'

Save and close the file and then run below command to restart postfix service.

# service postfix restart

Run the below command to ensure that Postfix can find the first domain and it should return '1' to be successful.

# postmap -q mysql:/etc/postfix/

Now test Postfix to verify that it can find the aliases by entering the following command by replacing with the actual alias you used.

# postmap -q mysql:/etc/postfix/

You should again receive 1 as the output. Then test Postfix to verify that it can find the aliases by entering the following command.

# postmap -q mysql:/etc/postfix/

This will return the email address to which the alias forwards as shown in the image below.

Potfix conf testing

Next we will configure the '/etc/postfix/' file. Before making changes in it save it copy first.

# cp /etc/postfix/ /etc/postfix/

Then open the configuration file for editing and uncomment the two lines starting with 'submission' and 'smtps' and the block of lines starting with '-o' after each which should be like the below.

# vim /etc/postfix/


Save the configuration and then run command below to restart postfix services, and you have done your postfix configurations successfully.

# service postfix restart

Dovecot Configuration Setup

Dovecot allows users to log in and check their email using POP3 and IMAP. Here we will configure Dovecot to force users to use SSL when they connect so that their passwords are never sent to the server in plain text. Let's start by copying all original configurations before making any changes.

root@ubuntu-16:~# cp /etc/dovecot/dovecot.conf /etc/dovecot/
root@ubuntu-16:~# cp /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/
root@ubuntu-16:~# cp /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/
root@ubuntu-16:~# cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/
root@ubuntu-16:~# cp /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/
root@ubuntu-16:~# cp /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/
# vim /etc/dovecot/dovecot.conf
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol

dovecont conf

After saving this, open the '/etc/dovecot/conf.d/10-mail.conf' file to modify the following variables within the configuration file which controls how Dovecot interacts with the server’s file system to store and retrieve messages.

# vim /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail

Run below command to create the folder for the domain and then create the 'vmail' user with a user and group id of '5000'. This user will be in charge of reading mail from the server.

# mkdir -p /var/mail/vhosts/
# groupadd -g 5000 vmail
# useradd -g vmail -u 5000 vmail -d /var/mail

Then change the owner of the '/var/mail/' folder and its contents to belong to vmail user.

dovcot setup

Open the user authentication file as shown below and disable plain-text authentication by uncommenting the below line.

#vim /etc/dovecot/conf.d/10-auth.conf
auth_mechanisms = plain login

Within the same file comment the system user login line and enable MySQL authentication by uncommenting the 'auth-sql.conf.ext' line as shown.

#!include auth-system.conf.ext
!include auth-sql.conf.ext

Save the configuration file and then edit the '/etc/dovecot/conf.d/auth-sql.conf.ext' file with the authentication information by pasting the following lines into in the file as shown below.

# vim /etc/dovecot/conf.d/auth-sql.conf.ext

sql auth

After saving update the '/etc/dovecot/dovecot-sql.conf.ext' file with the custom MySQL connection information.

# vim /etc/dovecot/dovecot-sql.conf.ext
# Database driver: mysql, pgsql, sqlite
driver = mysql
connect = host= dbname=mailserver user=mailuser password=mailuser_pass
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

Save the file and change the permissions, owner and group of the /etc/dovecot/ directory to vmail and dovecot.

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

Disable unencrypted IMAP and POP3 by setting the protocols’ ports to 0, as shown below. Ensure that the entries for port and ssl below the IMAPS and pop3s entries are uncommented.

service imap-login {
inet_listener imap {
#port = 143
inet_listener imaps {
port = 993
ssl = yes

service pop3-login {
inet_listener pop3 {
port = 0
inet_listener pop3s {
port = 995
ssl = yes
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =

Search the service auth section and configure it as shown.

service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Its default
# permissions make it readable only by root, but you may need to relax these
# permissions. Users that have access to this socket are able to get a list
# of all usernames and get results of everyone's userdb lookups.
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix

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

# Postfix smtp-auth
user = dovecot

Uncomment the user line and set it to vmail under service auth-section.

service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
#user = root
user = vmail

That's it , now save the configuration file and run below command to restart Dovecot service.

# service dovecot restart

Now set up any test account in an email client to ensure that everything is working. Provide the full email address, including your domain name and the password that you added to the MariaDB table for you email address. Then try sending an email to this account from an outside email account and then reply to it. After that check the mail log file in /var/log/mail.log for an incoming message, and the second block for an outgoing message.

Setup Roundcube for Webmail Interface

You can use email client which supports 'smtp' and 'pop/imap', but webmail part is completely optional.

Run the below command to install Roundcube along with its plugins on your Ubuntu 16.04 server and press 'Y' key to start the installation process.

# apt-get install roundcube roundcube-plugins roundcube-plugins-extra

installing roundcube

During the installation, you will be asked to for a database installed and configured before it can be used. This is optional and we will be selecting 'No' here as we have already setup the database.

roundcube-core config

After installation, open its configuration file using any editor and put the following parameters in it as shown.

# vim /etc/roundcube/
$rcmail_config['default_host'] = 'localhost';
$rcmail_config['imap_cache'] = memcache;
$rcmail_config['messages_cache'] = db

Save and close the file after making your changes. Then create a virtual host in your web server and launch your favorite web browser to begin configuring Roundcube. The first step of Roundcube’s graphical configuration is an environment check. Click on the NEXT button at the bottom of the page to continue.


Congratulation, we have successfully set up a mail server using Postfix, MariaDB, Dovecot and Roundcube on Ubuntu 16.04. If DNS records have not been created for the mail server yet then do now. Once the DNS records have propagated, email will be delivered via the new mail server. Now you can add new domains, email addresses, and aliases for the users by simply adding a new line to the appropriate MySQL table and enjoy communication over your newly build Ubuntu mail server.

8 Comments... add one

  1. I cannot get dovecot to authorize logins from thunderbird or iphone.

    from dovecot.log
    imap-login: Info: Aborted login (no auth attempts in 0 secs): user=,

    testing mariadb, everything passes (returns 1) except:

    postmap -q mysql:/etc/postfix/

    This just returns command prompt. Not sure what's going on...

    • FYI = replaced with my real domain

      This shows the 2 domains i have in db just fine:
      MariaDB [mailserver]> SELECT * FROM mailserver.virtual_domains;

  2. I have this working now.

    correct virtual mailbox domains file:
    user = mailuser
    password = *****
    hosts =
    dbname = mailserver
    query = SELECT 1 FROM virtual_domains WHERE name='%s'

    This statement doesn't say which .conf file
    "Disable unencrypted IMAP and POP3 by setting the protocols’ ports to 0, as shown below. Ensure that the entries for port and ssl below the IMAPS and pop3s entries are uncommented."

    It is /etc/dovecot/conf.d/10-master.conf

    Then I needed to tell dovecot to use CRYPT.

  3. Can someone tell me how to configure file size attachment to a certain size (e.g. 30MB) for both postfix and dovecot?



Leave a Comment