Set 102014

Postfix & Dovecot

(I have written this article in english since I wasn’t able to find any updated guide about this subject in any language).

DISCLAIMER. this is a very basic configuration. Not intended for production environment. Use at your own risk.

I have a small mailserver handling very few domains with mailboxes  for may friends and relatives an it have been working fine for the last 8 years.
But  it is based on the old CentOS 5 + sendmail and I think it is time to upgrade!

So, in order to test the new future configuration, I have performed a  CentOS 7 minimum install  on a virtual machine and tried to configure the  minimum amount of packages to have it working.

Now let’s start!

First of all, good news: on CentOS 7 both the stock postfix and dovecot packages have full mysql support without the need for enabling external repos or recompiling them from the source.


Mysql have been replaced by MariaDB that is mainly compatible.

Ask yum to install mariadb and mariadb-server packages.

[root@server03 ~]# yum install mariadb mariadbserver

Start and enable the service

[root@server03 ~]# systemctl start mariadb
[root@server03 ~]# systemctl enable mariadb

(please note the new SystemD commands. You can still use the service command for compatibility, but it will be redirected to systemctl)

Then launch

[root@server03 ~]# mysql_secure_installation

and answer all the questions (change root password….)

Now it is time to create database and tables for our simple installation.

Enter the mysql console:

[root@server03 ~]# mysql -uroot -p
Enter password: 

(enter the root mariaDB password you have set during secure installation process)

Create the database:

MariaDB [(none)]> create database mailserver;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> 

Select database:

MariaDB [(none)]> use mailserver;

Create user table (paste the following SQL):

CREATE TABLE `users` ( `email` varchar(200) NOT NULL,
 `password` varchar(128) NOT NULL,
 `enabled` int(11) NOT NULL DEFAULT '1', 
 `username` varchar(45) DEFAULT NULL, 

This table will be used by postfix and dovecot to select valid mailboxes and to authenticate matching users.

The fields are self-explanatory.
Just one note: even if Dovecot will use email as username, the field username will be used for SMTP auth (in the next article) since I prefer my ordinary mail users (IMAP, POP) not to be able to send email using the resident SMTP service. Only users with ‘username’ set will be able to do it.

Now you need to create the domains table.

 `domains` ( `domain` varchar(200) NOT NULL,
 `enabled` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`domain`))

In this table you will put all the domains you decide to recive mail for.

Now the alias TABLE:

CREATE TABLE `aliases` ( `email` varchar(128) NOT NULL,
`alias` varchar(255) NOT NULL,
`enabled` int(11) DEFAULT '1',

This table will contain all your aliases. For example a global address can be routed to both,

Grant privileges to a new user postfix on the whole database.

grant select on mailserver.* to postfix@localhost identified by 'yoursecretpassword'

Add some relevant data in the above tables:

insert into users set email='', password='segretissima', username='paperino';
insert into users set email='', password='segretissima', username='pluto';
insert into domains set domain='';
insert into aliases set email='', alias=','

This way you have created two mailboxes and a global alias routing to both of them.

Moreover you have just told your server to accept incoming emails for domain.

thats’all for the database!

POSTFIX configuration

Postfix already installed and enabled, otherwise:

[root@server03 ~]# yum install postfix
[root@server03 ~]# systemctl enable postfix
[root@server03 ~]# systemctl start postfix

save your configuration

[root@server03 ~]# cd /etc/postfix
[root@server03 ~]# cp

Now you can edit your

This is a very basic configuration example:

queue_directory = /var/spool/postfix
data_directory = /var/lib/postfix
mail_owner = postfix

#replace with your FQDN 
myhostname =

#listen on all interfaces (not only localhost)
inet_interfaces = all

#enable IPV6 too
inet_protocols = all

smtpd_helo_required = yes


unknown_local_recipient_reject_code = 550
mynetworks =

in_flow_delay = 3s

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases

mail_spool_directory = /var/spool/mail

#replace with your personal banner
smtpd_banner = $myhostname benvenuto sul server di posta della Famiglia Vettore

debug_peer_level = 2

debugger_command =
         ddd $daemon_directory/$process_name $process_id & sleep 5

sendmail_path = /usr/sbin/sendmail.postfix

newaliases_path = /usr/bin/newaliases.postfix

mailq_path = /usr/bin/mailq.postfix

html_directory = no

#place where virtual databases are located
virtual_mailbox_domains = mysql:/etc/postfix/
virtual_mailbox_maps = mysql:/etc/postfix/
virtual_alias_maps = mysql:/etc/postfix/

#delivery transport: dovecot
dovecozz_destination_recipient_limit = 1

virtual_minimum_uid = 150
virtual_uid_maps = static:150
virtual_gid_maps = static:150

Create system user vmail:vmail with an high uid and gid (150 in the above example) so it won’t interfere with ordinary system users. Create a directory to store incoming emails.

[root@server03 ~]# useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual mailbox" vmail
[root@server03 ~]# groupadd -g 150 vmail
[root@server03 ~]# mkdir /var/vmail
[root@server03 ~]# chown vmail:vmail /var/vmail

For a simple configuration a single user can be enough.

Now you have to create database connectors as stated in the above configuration file.

For example /etc/postfix/

user = postfix
password = yuorsecretpassword
hosts =
dbname = mailserver
query = SELECT 1 FROM domains WHERE domain='%s' AND enabled=1 

This is self-explanatory: when postfix look for a domain name it can find here instructions to connect to the database and query it.

You can test your configuration as follows:

[root@server03 ~]# postmap -q mysql:/etc/postfix/

If is in your domains table it willl return 1.

Similarly you can setup the other two connectors.

/etc/postfix/ :

user = postfix
password = yoursecretpassword
hosts =
dbname = mailserver
query = SELECT 1 FROM users where email='%s' and enabled=1 


user = postfix
password = yoursecretpassword
hosts =
dbname = mailserver
query = SELECT alias FROM aliases WHERE email='%s' AND enabled=1 

Finally, you should tell postfix to use dovecot to deliver local mail.

Add this to your /etc/postfix/

dovecozz unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}

Service name (‘dovecozz’ in this case) must match the configuration in your (virtual_transport=dovecozz).

DOVECOT installation and configuration

First of all install the packages, activate and start dovecot the service:

[root@server03 ~]# yum install dovecot dovecot-mysql
[root@server03 ~]# systemctl enable dovecot
[root@server03 ~]# systemctl start dovecot

Very few configurations are needed.

In your /etc/dovecot/dovecot.conf add the following lines:


first_valid_uid = 150
last_valid_uid = 150

The first line is the most important: it tells dovecot how to store incoming emails.

I have choosen this simple schema: for example email to will be stored in:


The other configuration lines simply tell dovecot to use the user vmail we have created above.

Similarly to other services the new dovecot configurations follow the new scheme of the single file in the ./conf.d folder.

So you will find the auth conf in


You have to tell dovecot to use mysql backend. Edit the above file, comment (adding #) all the !include line at the end of the file.

Than add

!include authmysql.conf.ext

This tells dovecot to look in /etc/dovecot/conf.d/auth-mysql.conf.ext for the auth configuration.

This file doesn’t exist so we have to create it.
After that insert the following lines:

passdb {
   args = /etc/dovecot/dovecot-sql.conf

userdb  {
        args = uid=150 gid=150 home=/var/vmail/%d/%n allow_all_users=yes

Please note in the passdb section there is a reference to /etc/dovecot/dovecot-sql.conf .

This is the real connector.

We can create the connector as follows:


default_pass_scheme = PLAIN 
connect= host= port=3306 dbname=mailserver user=postfix password=yoursecretpassword
password_query = SELECT password, email as user  FROM users where email='%u' AND enabled=1

Please note in the above connector I have stated to use a PLAIN password scheme.

This means your password will be stored in plain text. If U think this can be a security issue you can choose CRAM-MD5, CRYPT or more complex schemes.

Time for test now!

TESTING the configuration

Restart the dovecot and postfix services.

Telnet your server from localhost:

[root@server03 ~]# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 benvenuto sul server di posta della Famiglia Vettore
helo pippolo
250 2.1.0 Ok
250 2.1.5 Ok
354 End data with .
subject: test mail from localhost 

This is the body of the mail
250 2.0.0 Ok: queued as 7630680FF9A7
221 2.0.0 Bye
Connection closed by foreign host.
[root@server03 ~]# 

If everything went fine, you should find something like this at the end of your /var/log/maillog

Sep 10 15:04:03 server03 postfix/smtpd[23520]: connect from localhost[::1]
Sep 10 15:04:34 server03 postfix/smtpd[23520]: 7630680FF9A7: client=localhost[::1]
Sep 10 15:05:06 server03 postfix/cleanup[23530]: 7630680FF9A7: messageid=<>
Sep 10 15:05:06 server03 postfix/qmgr[23074]: 7630680FF9A7: from=, size=378, nrcpt=1 (queue active)
Sep 10 15:05:09 server03 postfix/smtpd[23520]: disconnect from localhost[::1]
Sep 10 15:05:23 server03 dovecot: lda( msgid=<>: saved mail to INBOX
Sep 10 15:05:23 server03 postfix/pipe[23533]: 7630680FF9A7: to=, relay=dovecozz, delay=59, delays=42/0.02/0/16, dsn=2.0.0, status=sent (delivered via dovecozz service)
Sep 10 15:05:23 server03 postfix/qmgr[23074]: 7630680FF9A7: removed

You shold find a newly created folders in /var/vmail/ and your incoming mail in /var/vmail/

Try the above example replacing the destination with and check the mail routed to both your alias addresses.

You can try to telnet from a remote host but pay attention to kick or (better) configure your firewallD service. Pay attention: iptables and ip6tables are no longer installed by default!.


In the next articles I will explain how to enable authenticated SMTP with SSL and how to fight SPAM and VIRUSES.

Have fun!

  19 Risposte a “Centos 7.x (or RHEL) very simple configuration of a mailserver with postfix, dovecot & mysql (mariaDB) – part 1”

  1. When i go in step:

    chown vmail:vmail /var/vmail

    there is an error: utilizador inválido

    any solution?

    • I think your error it is the translation for “invalid user”. Check user “vmail” exists in your system!

      • Sorry my fault! pasting the code from my server the minus (“-“) sign disappeared 🙁
        So the useradd and groupadd command were wrong.

        Fixed commands:

        [root@server03 ~]# useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c 
        [root@server03 ~]# groupadd -g 150 vmail
        [root@server03 ~]# mkdir /var/vmail
        [root@server03 ~]# chown vmail:vmail /var/vmail

        thank you for your feedback!

        • Thanks for the help…

          In line: useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c

          I got the error: useradd: option requires an argument — ‘c’

          • any solution for this?

          • The solution is to run useradd and groupadd again with the correct (fixed) syntax.
            This way you create user “vmail” and you can chown your dir

          • In your fix solution you have…
            useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c

            I think you dont paste all of the code because you miss the name of user (vmail) and the option ‘-c’ i dont understand what do.

            I type this (withou option -c and with user ‘vmail’):
            useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin vmail
            The user was created…
            My question is… Is this correct?
            and You type “-g mail” is this correct or we need to change to “-g vmail”

            Thanks for your help.

          • You are absolutely right for the truncated line.
            The full command is:

            useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual mailbox" vmail

            The group “mail” is correct. It is the same group of postfix user.
            So your command (without -c) is OK.

            Thank you for your help in debugging my article.
            Hope to do better next time 🙂

  2. At File:/etc/postfix/
    In Line Add this to your /etc/postfix/
    dovecozz unix n n pipe flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver f ${sender} d ${recipient}

    When i restart my postfix Service I get the error
    bad value “Pipe”

    any solution?

  3. When i restart my service DOVECOT i got the error:

    Dovecot: Fatal: Error in configuration file: /etc/dovecot/conf.d/auth-mysql.conf.ext
    Line 1: expecting ‘=’

    • check your syntax.
      This is pasted from my working server:

      passdb {
         args = /etc/dovecot/dovecot-sql.conf
      userdb  {
              args = uid=150 gid=150 home=/var/vmail/%d/%n allow_all_users=yes
  4. When you are testing and Telnet your server from localhost:… you write:

    helo pippolo

    what is the meaning of this?

  5. Great work!

    Waiting for… The NEXT STEP! 🙂

  6. Hi, thanks for your tutorial.
    I have a question, all of my setting is complete but I still can’t sent mail :

    when I test to send email via telnet, then I have error status in var/log/maillog

    Error dovecot:
    “Initialization failed :Namespace ” mkdir(var/vmail/ failed; Permission denied (euid=150(vmail) egid=150(vmail) missing +w perm: /var/vmail, UNIX perms appear ok (ACL/MAC wrong?)) ”

    what makes the error ?


    • Your “vmail” user hasn’t write permission on the /var/vmail dir.
      try chowning it:

      [root@server03 ~]# chown vmail:vmail /var/vmail

      It should be ok.

  7. Forse sarà pignoleria ma il comando yum per l’installazione di mariadb va corretto perché manca un trattino:
    yum install mariadb mariadbserver non fuzniona
    yum install mariadb mariadb-server FUNZIONA

 Lascia un commento

Puoi usare questi tag e attributi HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>