How to Configure Postfix and Dovecot with Virtual Domain Users in Linux – Part 2

In the previous article of this series we explained how to set up and manage the mail server database securely using phpMyAdmin.

Requirement:

  1. Install Postfix Mail Server and Dovecot with MariaDB – Part 1
Configure Postfix and Dovecot with Virtual Domain Users
Configure Postfix and Dovecot with Virtual Domain Users – Part 2

Now it’s time to configure the internal programs that will make sending and receiving emails a reality: Postfix and Dovecot (to handle outgoing and incoming emails, respectively).

Configuring Postfix Mail Server

Before you begin configuring Postfix, it would be worth and well to take a look at its man pages here, putting special emphasis on the section titled “Information for new Postfix users“. If you do, you will find it easier to follow along with this tutorial.

In few words, you should know that there are two configuration files for Postfix:

  1. /etc/postfix/main.cf (Postfix configuration parameters, refer to man 5 postconf for more details).
  2. /etc/postfix/master.cf (Postfix master daemon configuraton, see man 5 master for further details).

In /etc/postfix/main.cf, locate (or add, if necessary) the following lines and make sure they match the values indicated below:

main.cf
append_dot_mydomain = no
biff = no
config_directory = /etc/postfix
dovecot_destination_recipient_limit = 1
message_size_limit = 4194304
readme_directory = no
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (CentOS)
smtpd_tls_cert_file = /etc/pki/dovecot/certs/dovecot.pem
smtpd_tls_key_file = /etc/pki/dovecot/private/dovecot.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes
virtual_transport = dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

The next three settings are of special importance. In the files indicated in yellow we will configure Postfix’s access to the Domains_tbl, Users_tbl, and Alias_tbl tables:

virtual_mailbox_domains = mysql:/etc/postfix/mariadb-vdomains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mariadb-vusers.cf
virtual_alias_maps = mysql:/etc/postfix/mariadb-valias.cf

Note that you can choose different file names above, as long as you make sure to create them and insert the following contents in them. In each case, replace YourPassword with the password you chose for the dba user in Part 1, or you can also use the MariaDB root credentials for user and password below.

Also, make sure you use the exact same names of the email server database and tables created in Part 1.

In /etc/postfix/mariadb-vdomains.cf:

mariadb-vdomains.cf
user = dba
password = YourPassword
hosts = 127.0.0.1
dbname = EmailServer_db
query = SELECT 1 FROM Domains_tbl WHERE DomainName='%s'

In /etc/postfix/mariadb-vusers.cf:

mariadb-vusers.cf
user = dba
password = YourPassword
hosts = 127.0.0.1
dbname = EmailServer_db
query = SELECT 1 FROM Users_tbl WHERE Email='%s'

In /etc/postfix/mariadb-valias.cf:

mariadb-valias.cf
user = dba
password = YourPassword
hosts = 127.0.0.1
dbname = EmailServer_db
query = SELECT Destination FROM Alias_tbl WHERE Source='%s'

Finally, don’t forget to change the permissions to these files to 640:

# chmod 640 /etc/postfix/mariadb-vdomains.cf
# chmod 640 /etc/postfix/mariadb-vusers.cf
# chmod 640 /etc/postfix/mariadb-valias.cf

And the ownership to user root and group postfix:

# chown root:postfix /etc/postfix/mariadb-vdomains.cf
# chown root:postfix /etc/postfix/mariadb-vusers.cf
# chown root:postfix /etc/postfix/mariadb-valias.cf

Next, to enable secure connections we need to make sure the following settings are uncommented (or added, if necessary) in /etc/postfix/master.cf:

master.cf
submission inet n       -       n       -       -       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_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
pickup    unix  n       -       n       60      1       pickup
cleanup   unix  n       -       n       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       n       -       -       smtp
relay     unix  -       -       n       -       -       smtp

showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
retry     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
#virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache

Note: The indentation in the lines beginning with the -o option is critical; otherwise postfix check will return an error:

Check Postfix Configuration
Check Postfix Configuration

Before you save changes, add the following lines at the bottom of the file:

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

At this point it is essential to check whether Postfix has access to the database tables and the domains, accounts, and alias that we created in Part 1.

To do so, we will use the postmap command, an utility to test communication with the tables Postfix will look up during operation, but first and foremost we’ll need to restart postfix:

# systemctl postfix restart
# postmap -q linuxnewz.com mysql:/etc/postfix/mariadb-vdomains.cf
# postmap -q someotherdomain.com mysql:/etc/postfix/mariadb-vdomains.cf
# postmap -q [email protected] mysql:/etc/postfix/mariadb-vusers.cf
# postmap -q [email protected] mysql:/etc/postfix/mariadb-vusers.cf
# postmap -q [email protected] mysql:/etc/postfix/mariadb-vusers.cf
# postmap -q [email protected] mysql:/etc/postfix/mariadb-valias.cf

In the image below we can see that for existing records in the database, a 1 is returned. Otherwise, nothing is displayed back to the screen. In the case of the alias check, note that the actual email account the alias is mapped to is returned:

Check Postfix Table Communication
Check Postfix Table Communication

Note that we are NOT authenticating against the credentials set for each email account, we are only testing the ability of Postfix to detect those records in the database.

Thus, if you get a different output than above, make sure you are using a valid user / password pair in mariadb-vdomains.cf, mariadb-vusers.cf, and mariadb-valias.cf (or whatever you chose to call those files).

Configuring Dovecot

As an IMAP / POP3 server, Dovecot provides a way for users through a Mail User Agent (MUA, or also known as client), such as Thunderbird or Outlook, to name a few examples to access their mail.

To begin, let’s create a user and a group to handle emails (we will need this as our email accounts are not associated with a system user). You can use another UID and GID (other than 5000 as we do below) as long as it’s not in use and is a high number:

# groupadd -g 5000 vmail 
# useradd -g vmail -u 5000 vmail -d /home/vmail -m

The settings for Dovecot are split across several configuration files (make sure the following lines are uncommented and / or edit them to match the settings indicated below).

In /etc/dovecot/dovecot.conf:

dovecot.cf
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap pop3 lmtp
!include conf.d/*.conf
!include_try local.conf

In /etc/dovecot/conf.d/10-auth.conf (only enable authentication through SQL and leave other authentication methods commented out):

10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext

In /etc/dovecot/conf.d/auth-sql.conf.ext (note that we will store emails within a directory named yourdomain.com inside /home/vmail, which you need to create if it doesn’t exist. In our case we did mkdir /home/vmail/linuxnewz.com to manage emails for that domain):

auth-sql.conf.ext
passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/home/vmail/%d/%n/Maildir
}

Individual inboxes for user accounts will be created when emails for such accounts are first received.

In /etc/dovecot/conf.d/10-mail.conf:

10-mail.conf
mail_location = maildir:/home/vmail/%d/%n/Maildir
namespace inbox {
  inbox = yes
}
mail_privileged_group = mail
mbox_write_locks = fcntl

In /etc/dovecot/conf.d/10-master.conf:

10-master.conf
service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
   mode = 0600
   user = postfix
   group = postfix
  }
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
  unix_listener auth-userdb {
   mode = 0600
   user = vmail
  }
  user = dovecot
}
service auth-worker {
  user = vmail
}
service dict {
  unix_listener dict {
  }
}

In /etc/dovecot/conf.d/10-ssl.conf (replace the certificate and key paths if you are planning on using a certificate signed by a CA):

10-ssl.conf
ssl = required
ssl_cert = </etc/pki/dovecot/certs/dovecot.pem
ssl_key = </etc/pki/dovecot/private/dovecot.pem

In /etc/dovecot/dovecot-sql.conf.ext enter your database information and the credentials of the administrative user created in Part 1.

Important: if your password contains an asterisk (#), you will need to enclose the connect string as indicated in the example below:

dovecot-sql.conf.ext
driver = mysql
connect = "host=127.0.0.1 dbname=EmailServer_db user=dba password=PassWith#Here"
default_pass_scheme = SHA512-CRYPT
password_query = SELECT Email as User, password FROM Users_tbl WHERE Email='%u';

Additionally, you can configure logging for Dovecot to be separate from Postfix in /etc/dovecot/conf.d/10-logging.conf:

log_path = /var/log/dovecot.log

Finally, make sure the Dovecot log is accessible for user dovecot:

# chown vmail:dovecot /var/log/dovecot.log
# chmod 660 /var/log/dovecot.log

Verify and Fix Postifix Configuration and Enable SMTP, POP3, and IMAP in Firewall

If you happen to run into any issues while configuring Postfix and / or Dovecot, instead of submitting all of the configuration files to ask for help, you can get a configuration summary (uncommented lines only) with:

# postconf –n # Summary for /etc/postfix/main.cf
# postconf –M # Summary for /etc/postfix/master.cf
# doveconf –n # Summary of all configuration files for Dovecot

In addition, make sure that the email inboxes are readable by vmail only:

# chown –R vmail:vmail /home/vmail

Configuration files should also be readable by vmail and dovecot users:

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

Finally, make sure you enable SMTP, POP3, and IMAP through the firewall:

# firewall-cmd --add-port=143/tcp
# firewall-cmd --add-port=143/tcp --permanent
# firewall-cmd --add-port=110/tcp
# firewall-cmd --add-port=110/tcp --permanent
# firewall-cmd --add-port=587/tcp
# firewall-cmd --add-port=587/tcp --permanent

Configure Thunderbird as an Email Client for Postfix

Having secured access through the firewall for the ports used in email communications, it’s time to configure an email client. Using [email protected] and its corresponding password, along with mail.linuxnewz.com as IMAP (or POP3) and SMTP server we are ready to start sending and receiving emails to and from such account:

Postfix: Configure Thunderbird Client
Postfix: Configure Thunderbird Client

You can safely disregard the warning message that is shown because you are using a certificate that is not signed by a trusted 3rd-party CA:

Thunderbird: Add Security Exception
Thunderbird: Add Security Exception

Let’s compose a brief test email and click Send:

Compose A Email on Thunderbird
Compose A Email on Thunderbird

When prompted to accept the self-signed certificate for the outgoing server, confirm it previously as before:

Thunderbird: Accept SSL Certificate
Thunderbird: Accept SSL Certificate

Finally, go to the destination email to see if you received the email that was just sent. If so, reply to it and see if it is delivered back to the source email inbox (otherwise, refer to the Postfix log at /var/log/maillog or the Dovecot log at /var/log/dovecot.log for troubleshooting information):

Verify Postfix and Dovecot Email Delivery
Verify Postfix and Dovecot Email Delivery

You now have a working Postfix and Dovecot email server and can start sending and receiving emails.

Summary

In this article we have explained how to configure Postfix and Dovecot to handle email traffic in your Linux server. If something does not work as indicated in this article, make sure you take time to check the Postfix and Dovecot documentation.

Please note that although setting up a Postfix mail server is not an easy task, it is a rewarding experience for every system administrator.

If after going through the docs you find yourself still struggling with Postfix and / or Dovecot, feel free to drop us a note using the comment form below and we will be glad to help you (don’t forget to upload to an online storage service the Postfix and Dovecot configuration as retrieved using postconf and doveconf as outlined in this article).

If you read this far, tweet to the author to show them you care. Tweet a thanks
Gabriel Cánepa
Gabriel Cánepa is a GNU/Linux sysadmin and web developer from Villa Mercedes, San Luis, Argentina. He works for a worldwide leading consumer product company and takes great pleasure in using FOSS tools to increase productivity in all areas of his daily work.

Each tutorial at TecMint is created by a team of experienced Linux system administrators so that it meets our high-quality standards.

Join the TecMint Weekly Newsletter (More Than 156,129 Linux Enthusiasts Have Subscribed)
Was this article helpful? Please add a comment or buy me a coffee to show your appreciation.

100 thoughts on “How to Configure Postfix and Dovecot with Virtual Domain Users in Linux – Part 2”

  1. I have successfully installed virtual domain postfix with dovecot. my server supports regexp, but i am unable to write rule for following

    abc.mydomain.com should send/receive email to/from abc.mydomain.com only
    xyz.mydomain.com should send/receive email to/from xyz.mydomain.com only
    abc.blahdomain.com should send/receive email to/from abc.blahdomain.com only
    

    it didn’t work with my regex, Please guide.

    Reply
  2. Hi,

    For me Ubuntu-18.04 dovecot lib path is /usr/lib/dovecot not /usr/libexec.

    Re
    dovecot unix – n n – – pipe
    flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop}

    Reply
  3. Hi, knowledgeable once. Can you please answer one of my question

    drwsrws--T  4  vmail                vmail 4096 Mar 14 17:15 .
    drwxr-xr-x 16   vmail                vmail 4096 Mar 14 13:15 ..
    drwxrws--T  4 fvmail                vmail 4096 Mar 14 17:11 fzela.com
    drwxrws--T  3   vmail               vmail 4096 Mar 14 17:15 fzmail.com
    

    I want mailbox structure like this where fzela.com and fzmail.com are domain which contain permission of root directory and inside domain for example fzela.com , I want user permission like this

    drwxrws--T 4    vmail                            vmail 4096 Mar 14 17:11 .
    drwsrws--T 4    vmail                            vmail 4096 Mar 14 17:15 ..
    drwx--S--- 3       fzinnus123.fzela         vmail 4096 Mar 14 17:10 fzinnus123
    drwx--S--- 3       fzinnus123.fzela         vmail 4096 Mar 14 17:11 fzsaran123
    

    where fzinnus123 and fzsaran123 are users for fzela.com domain.

    I tried a lots but unable to get in mycase my using virtual users

    Reply
  4. I love these kinds of articles, do any of them work?

    For all us newer users, this article would be fantastic if….Just post the complete config file for postfix/dovecot….Do the mods, file creation, databases, etc and done.

    Reply
  5. Hi,

    I have configured a local email server according to your article. I am having a problem when connecting through thunderbird. It keeps saying the password is incorrect. But the password is correct. The dovecot.log gives the authentication failed error. Could you please help me on this?

    Reply
  6. Hello Gabriel Cánepa, well done on the tutorial, I managed to follow it through and though I had to tweak a bit to get things going I finally did it and it’s working fine, I can receive messages!

    But I am afraid I cannot send such, sending to other addresses which doesn’t belong to the local host such @gmail.com, @yahoo.com, etc. fails, as if the server is trying to connect them using SMTP.

    Here are few errors which might help you straight what I mean out:

    Sep 28 12:51:40 us00 postfix/smtp[2491]: connect to mx10.mailspamprotection.com[184.154.177.50]:25: Connection timed out
    Sep 28 12:51:40 us00 postfix/smtp[2491]: A25613F0E5: to=, relay=none, delay=227, delays=72/0.03/155/0, dsn=4.4.1, status=deferred (connect to mx10.mailspamprotection.com[184.154.177.50]:25: Connection timed out)

    Sep 28 12:51:35 us00 postfix/smtp[2490]: A42F93F0AC: to=, relay=none, delay=2358, delays=2208/0.02/150/0, dsn=4.4.1, status=deferred (connect to alt4.gmail-smtp-in.l.google.com[74.125.193.27]:25: Connection timed out)
    Sep 28 12:51:35 us00 postfix/smtp[2493]: 1692A3F0D8: to=, relay=none, delay=2278, delays=2128/0.04/150/0, dsn=4.4.1, status=deferred (connect to alt4.gmail-smtp-in.l.google.com[74.125.193.27]:25: Connection timed out)

    Please bare in mind that these two are email addresses hosted externally.

    I have followed all settings in the tutorial, my MX record is pointing to:mx.domain.tld, PTR to mx.domain.tld and mx.domain.tld A Record.

    I am honestly not sure what shall I tweak or do to make sure emails are going back and forth.

    Hopefully you can help!

    Reply
  7. Centos 7.5, pointing dovecot log file to /var/log/dovecot.log with suggested permissions results with the following error.

    Jul 02 21:03:48 domain.com dovecot[5708]: Can’t open log file /var/log/dovecot.log: Permission denied

    Event chmod 777 /var/log/dovecot.log didn’t help

    Reply
  8. The problem with de line argv=/usr/libexec/dovecot/deliver is the indentation. I have the error message “bad field count” until i put 2 spaces before the argv=.

    Reply
  9. help me! when i go to step

    Before you save changes, add the following lines at the bottom of the file:
    master.cf

    [root@sv conf.d]# postfix check
    /usr/sbin/postconf: fatal: file /etc/postfix/master.cf: line 129: bad field count

    Reply
    • @Le,

      Go the line 129 in master.cf file and check for any extra spaces or use correct spacing..

      dovecot   unix  -       n       n       -       -       pipe
        flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}
      
      Reply
      • There needs to be space before “flags” (or after pipe). If you are copying and pasting, you need to add it manually.

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

        Reply
  10. Hello Gabriel A. Cánepa,

    Me too have the same issue, Please comment on this. I have doubt the path “argv=/usr/libexec/dovecot/deliver” in line 134. Is it matching with your tutorial ? Actually that line needs a bit explanation, please consider. thanking you in advance….

    /usr/sbin/postconf: fatal: file /etc/postfix/master.cf: line 134: bad field count
    postfix/postlog: warning: inet_protocols: disabling IPv6 name/address support: Address family not supported by protocol
    postfix/postfix-script: fatal: cannot execute /usr/sbin/postconf!

    Reply

Leave a Reply to Ravi Saive Cancel reply

Thank you for taking the time to share your thoughts with us. We appreciate your decision to leave a comment and value your contribution to the discussion. It's important to note that we moderate all comments in accordance with our comment policy to ensure a respectful and constructive conversation.

Rest assured that your email address will remain private and will not be published or shared with anyone. We prioritize the privacy and security of our users.