Virtual Mail hosting on EL6

If you’re like me, you’ve searched other guides and ended up confused as hell as they are all different with different queries and end up not working with strange error messages. This guide is what I’ve done to enable virtual email hosting on SL6 with the user database in MySQL and still have the benefits of using SpamAssassin & Procmail.

Step 1
Firstly, we’re going to need to install at least the following packages:
* postfix (should already be installed)
* mysql-server
* mysql
* spamassassin
* procmail
* dovecot
* dovecot-mysql

This should pull in a number of other packages required.

NOTE: You will also need to install the spamass-milter and spamass-milter-postfix packages from epel.

Step 2
Start MySQL on the mail server.
# service start mysql

This is where we want to create the database for postfix etc to query. Use your favourite tool to do this – I used phpMyAdmin that I install on every system with MySQL installed. In this example, I used the database ‘virtualmail’ and created a user ‘postfix’ with password ‘postfix’. You should change these to something more suitable – even if its just the password.

Once you’ve created the database, create the cables with the following SQL:
`redirect` varchar(50) NOT NULL,
`to` varchar(100) NOT NULL,
`active` char(1) NOT NULL DEFAULT 'Y',
PRIMARY KEY (`redirect`)
`username` varchar(128) NOT NULL,
`domain` varchar(128) NOT NULL,
`password` varchar(128) NOT NULL,
`active` char(1) NOT NULL DEFAULT 'Y'

This should be fairly self explaining. The users table contains the username & domain of our email users as well as their password (which will be SHA512’ed) and if they are active or not (Y or N). The aliases table is exactly that – aliases to forward to somewhere else.

Step 4
Time to configure postfix for MySQL lookups. Edit /etc/postfix/ and add the following:
## Configuration for virtual domains.
virtual_alias_domains =
virtual_alias_maps = proxy:mysql:/etc/postfix/
virtual_mailbox_domains = proxy:mysql:/etc/postfix/
virtual_mailbox_maps = proxy:mysql:/etc/postfix/
virtual_mailbox_base = /vmail
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_transport = procmail
procmail_destination_recipient_limit = 1

We now need to create the config files to allow lookups. Create the following:
user = postfix
password = postfix
dbname = virtualmail
query = SELECT domain AS virtual FROM users WHERE domain='%s'
hosts = localhost

user = postfix
password = postfix
dbname = virtualmail
query = SELECT CONCAT(LOWER(CONCAT(domain,"/",username)),"/Maildir/") FROM users WHERE CONCAT(username,"@",domain)='%s' AND active="Y"
hosts = localhost

user = postfix
password = postfix
dbname = virtualmail
query = SELECT `to` FROM `aliases` WHERE `redirect` = "%s"
hosts = localhost

Step 5
Create the user which will own all the mailboxes. If you wish to user different UID/GIDs for each user, you will need to do this by editing the users table and adding a uid and gid field, then modifying the query as required. This seems to be covered very well elsewhere so I’ll skip it.
# adduser -u 5000 -d /vmail -s /sbin/nologin -U vmail

This creates a user with UID 5000, home directory as /vmail, sets the shell to /sbin/nologin to make sure nobody can log into the system with that accounts, and create a new usergroup with the same GID as UID.

Step 6
Configure SpamAssassin.
Edit /etc/postfix/ and add the following at the bottom:
smtpd_milters = unix:/var/run/spamass-milter/postfix/sock inet:
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Configure spamass-milter.
Edit /etc/sysconfig/spamass-milter to include a few extra flags to skip scanning email sent from local machines. I use:
EXTRA_FLAGS="-r -1 -i -i -i 2002:cb38:f71b::/48 -I"

This will automatically accept email from localhost, my LAN and my IPv6 subnet. The final -I option will also accept any email that has been sent using SMTP AUTH - ie an authenticated user.

We also want to update to the latest definitions.
# sa-update

Step 7
Now we want to configure procmail. We’ll use it as the system-wide delivery method.
Edit /etc/postfix/ and add the following:
procmail unix - n n - - pipe
-o flags=RO user=vmail argv=/usr/bin/procmail -t -m USER=${user}
EXTENSION=${extension} DOMAIN=${domain} /etc/postfix/procmailrc.common

We now want to create the global procmail file. This will run for *every* user on the system.
DOMAIN=`echo $DOMAIN | tr '[A-Z]' '[a-z]'`
USER=`echo $USER | tr '[A-Z]' '[a-z]'`
MKDIR=`mkdir -p $HOME/Maildir`

This will run the users own procmail and output all logging to their own procmail log. This is all done in the format /vmail/pm-$domain-$user.log. If you don’t want per-user procmail configuration, then remove the SWITCHRC line and the global config should take care of mail delivery for everyone.

SECURITY WARNING: As all mail is handled under the same UID:GID, it is possible for a malicious user to do things to other peoples mailboxes if you allow per-user procmailrc files from untrusted sources. I would only recommend having per-user procmailrc files on systems you have complete trust with users. If you find this questionable, remove the SWITCHRC line in the global procmail configuration.

Step 8
Now we configure Dovecot. I’m only going to cover the IMAP setup to keep things short, it can easily be adapted to POP3.

Create the file /etc/dovecot/dovecot-sql.conf.ext with the following:
driver = mysql
connect = host=localhost dbname=virtualmail user=postfix password=postfix
default_pass_scheme = SHA512
password_query = SELECT username, domain, password FROM users WHERE username = '%n' AND domain = '%d' AND active = "Y"

Edit /etc/dovecot/conf.d/auth-sql.conf.ext and alter it as follows:
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
userdb {
driver = static
args = uid=vmail gid=vmail home=/vmail/%s/%n/

Now I want to be nice to users that run Thunderbird etc and enable IMAP COMPRESS to let them get email a bit quicker. If you’re running a lot of users, this may be a bit heavy on the CPU, but try it anyway! Edit /etc/dovecot/conf.d/20-imap.conf and add the following:
mail_plugins = $mail_plugins imap_zlib

We also now want to add the zlib plugin in /etc/dovecot/conf.d/10-mail.conf and set the default location for email. Change the following values:
mail_location = maildir:/vmail/%d/%n/Maildir
mail_plugins = zlib

Lastly, we just need to enable SQL auth in /etc/dovecot/conf.d/10-auth.conf – uncomment the following line:
!include auth-sql.conf.ext

Step 9
Start it all up.

# chkconfig mysqld on
# chkconfig spamassassin on
# chkconfig spamass-milter on
# chkconfig dovecot on
# service mysqld start
# service spamassassin start
# service spamass-milter start
# service dovecot start

Step 10
Now you’ll want to configure your users. In your favourite mysql method, add users and then watch the mail flow. Note that the password is an SHA512 hash of the password – not the password in plain text! To create the hash, use the following:
# echo -n <password> | sha512sum

This will output something like the following:
# echo -n test | sha512sum
ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff -

If you have any corrections to this guide or suggestions, feel free to comment below!

Revision History:
2011-06-06 – Changed MD5 password hash to SHA512 for better security.
2011-06-07 – Altered PROCMAIL global file to deliver without a userspecific procmailrc. Also added logic to make a new users mail directory without having to manually create each directory. Now adding a new user is as simple as a database entry.
2012-02-19 – Changed to use of spamass-milter to avoid spam being forwarded to aliases without checking.


    • russianmonk on April 5, 2012 at 4:37 am
    • Reply


    Nice tutorial, thanks for the help. Where do you specify postfix to use sha512? I only see you specifying it in the dovecot config.

    1. Hi,

      In this example, I didn’t set up SMTP auth via Dovecot. To enable this, postfix will need to query the SASL service provided by Dovecot. To enable this, in /etc/postfix/ we want to enable:
      smtpd_recipient_restrictions = permit_sasl_authenticated reject_unauth_destination
      smtpd_sasl_type = dovecot
      smtpd_sasl_path = private/auth
      smtpd_sasl_auth_enable = yes
      smtpd_sasl_security_options = noanonymous, noplaintext
      smtpd_sasl_tls_security_options = noanonymous

      I also use the submission port for sending mail, leaving port 25 as a receive only. This means I have the following in /etc/postfix/
      submission inet n - n - - smtpd
      -o smtpd_tls_security_level=encrypt
      -o smtpd_sasl_auth_enable=yes
      -o smtpd_client_restrictions=permit_sasl_authenticated,reject
      -o milter_macro_daemon_name=ORIGINATING

      Finally, to enable Dovecot’s SASL service, check /etc/dovecot/conf.d/10-master.conf for:
      service auth {
      # Postfix smtp-auth
      unix_listener /var/spool/postfix/private/auth {
      mode = 0660
      user = postfix
      group = vmail

      As such, the submission port will now query user information via Dovecot and allow relay based on authentication.

Leave a Reply

Your email address will not be published.