Postfix, Dovecot, PostfixAdmin, Spamassassin on MySQL and CentOS 5.5

First, let’s handle the boring dependencies. Make sure you’re running as root.

# yum install httpd mysql php php-mysql wget

Set up SQL

# mysql_install_db –user=mysql
# mysql_secure_installation
# service mysql start
# mysql -p

You should now be staring at an SQL prompt. The following should be all of the necessary SQL commands for the entire HOWTO.

mysql> CREATE DATABASE postfix;
mysql> CREATE USER postfix@localhost IDENTIFIED BY ‘your_password’;
mysql> GRANT ALL PRIVILEGES ON postfix.* TO postfix;
mysql> grant SELECT ON postfix.* to ‘dovecot’@’localhost’ IDENTIFIED by ‘dovecot_password’;
mysql> grant SELECT, RELOAD, LOCK TABLES ON *.* to ‘backup’@’localhost’ IDENTIFIED by ‘backup’;
mysql> flush privileges;
mysql> exit

I’d really recommend writing a SQL backup script, and tossing it in your crontab. It’s optional, but a bloody good idea.

# env EDITOR=nano crontab -e

You might want to tune your Apache HTTPD configuration.

# nano /etc/httpd/conf/httpd.conf
# service httpd restart

Grab a copy of PostfixAdmin

# wget
# tar -zxvf postfixadmin-2.3.3.tar.gz
# mv postfixadmin-2.3.3.tar.gz postfixadmin
# mv postfixadmin /var/www/html/
# cd /var/www/html/postfixadmin
# nano

Follow the steps in to complete configuration. Basically, you’ll need to fill in some database information and create a password for adding administrators to PostfixAdmin. You want to point your web browser at http://www.yourdomain.tdl/postfixadmin/setup.php

It’ll display a checklist. Make sure all of your checks are good and it should make the necessary structure changes to the SQL database. Be sure to log in PostfixAdmin and make sure everything is happy. Otherwise you will be sad. Toss in some info, test email addresses and whatnot.

Enable CentOS Plus repo, then install postfix. The standard CentOS 5.5 repo doesn’t include the version of Postfix with SQL support. Why, I have no bloody clue. You want postfix 2.3.x. Be sure to exclude postfix from the updates and regular base repo. I snagged the version of PHP5 from the CentOS Testing repo as well, lot of webapps want it. I configured both additional repositories to only snag the packages I want.

Run postconf to see what is being supported.

# postconf -m
# postconf -a

If it doesn’t list MySQL on the first command and dovecot on the second, you have the wrong version of postfix. You probably messed up your repo hacking. Let’s ignore postifx for a moment, and move on into the realm of insanity. Here there be dragons.

Now, to snag dovecot. This is going to be ugly.

# rpm -Uvh
( or for x86_64, use )
# rpm –import
# yum install dovecot

You should have gotten dovecot 1.0.13. Recheck your repo config if you didn’t. For the love of the odd gods, do NOT use the standard CentOS repository for dovecot, which would be 1.0.7 or whatnot. It’s broken. Yes, do not ask me why anyone would keep a royally screwed up version in the main repository of a distribution known for testing and stability. I have no bloody clue.

# mkdir -p /var/vmail
# chmod 770 /var/vmail
# useradd -r -u 101 -g mail -d /var/vmail -s /sbin/nologin -c “Virtual mailbox” vmail
# chown vmail.mail /var/vmail
# cd /etc
# cp dovecot.conf dovecot.conf.original
# echo “” > dovecot.conf
# nano dovecot.conf

# ————————————
# ————————————
mail_location = maildir:/var/vmail/%d/%u
first_valid_uid = 101
last_valid_uid = 101
maildir_copy_with_hardlinks = yes
protocol imap {
mail_plugins = quota imap_quota
imap_client_workarounds = outlook-idle delay-newmail
protocol pop3 {
mail_plugins = quota
pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
protocol lda {
postmaster_address =
mail_plugins = quota
log_path = /var/log/dovecot-deliver.log
info_log_path = /var/log/dovecot-deliver.log
auth default {
# Having “login” also as a mechanism make sure outlook can use the auth smtpd as well
mechanisms = plain login
passdb sql {
args = /etc/dovecot/sql.conf
userdb sql {
args = /etc/dovecot/sql.conf
userdb prefetch {
user = nobody
socket listen {
master {
path = /var/run/dovecot/auth-master
mode = 0660
user = vmail
group = mail
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = mail
dict {
plugin {
# quota = maildir:storage=10240:messages=1000
# acl = vfile:/etc/dovecot/acls
trash = /etc/dovecot/trash.conf

Save it and get back to the command prompt. We still need to connect up to the SQL database that PostfixAdmin set up for us. Remember the dovecot password from that MySQL query earlier?

# nano /etc/dovecot/sql.conf

driver = mysql
connect = host=localhost dbname=postfix user=dovecot password=DOVECOT_SQL_password
user_query = SELECT concat(‘/var/vmail/’, maildir) as home, concat(‘maildir:/var/vmail/’, maildir) as mail, 101 AS uid, 12 AS gid, concat(‘maildir:storage=’, quota) AS quota FROM mailbox WHERE username = ‘%u’ AND active = ‘1’
password_query = SELECT username as user, password, concat(‘/var/vmail/’, maildir) as userdb_home, concat(‘maildir:/var/vmail/’, maildir) as userdb_mail, 101 as userdb_uid, 12 as userdb_gid FROM mailbox WHERE username = ‘%u’ AND active = ‘1’

# Config Notes:
# Note, query needs to be on ONE line
# Your web browser and paste will wrap it.

# nano /etc/dovecot/trash.conf

Paste in the folders you want created automatically

1 Spam
2 Trash

# cd /etc/postfix
# nano

Paste the following (yes, intended on the third line)

# Dovecot LDA
dovecot unix – n n – – pipe
flags=DRhu user=vmail:mail argv=/usr/libexec/dovecot/deliver -d ${recipient}

# cp
# echo “” >
# nano

Paste all of the following into

# Local Settings
myhostname = mail.example.tld # Change this, dude.
inet_interfaces = localhost, $myhostname
mynetworks = $config_directory/mynetworks
mydestination = localhost.$mydomain, localhost, $myhostname
#uncomment if you need relay_domains… do not list domains in both relay and virtual
#relay_domains = proxy:mysql:$config_directory/
# Virtual domain start
virtual_mailbox_domains = proxy:mysql:$config_directory/
virtual_mailbox_base = /var/vmail
virtual_mailbox_maps = proxy:mysql:$config_directory/
virtual_alias_maps = proxy:mysql:$config_directory/
virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/
virtual_minimum_uid = 101
virtual_uid_maps = static:101
virtual_gid_maps = static:12
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1

Save. Restart dovecot and postfix. Attempt to send mail back and forth. If it doesn’t work, go to /var/log/maillog and start reading.

If it works, and only once it works, we start on spamassassin.

# yum install spamassassin
# sa-update
# spamassassin –lint

If you get an error, then do the following:
– # rpm -q perl-Net-DNS perl-NetAddr-IP perl perl-IO-Socket-INET6
– # rpm -qi perl-IO-Socket-INET6
– # yum remove perl-IO-Socket-INET6
– # spamassassin –lint

If you didn’t get an error, start back here.

# adduser spamfilter -s /sbin/nologin
# nano /etc/postfix/

Add to bottom:

spamfilter unix – n n – – pipe
flags=Rq user=spamfilter argv=/usr/local/bin/spamfilter -f ${sender} — ${recipient}

Change from near top

smtp inet n – n – – smtpd
-o content_filter=spamfilter:dummy

# nano /usr/local/bin/spamfilter

Past in the following


/usr/bin/spamc | /usr/sbin/sendmail.postfix -i “$@”

exit $?

# chown spamfilter /usr/local/bin/spamfilter
# chmod 755 /usr/local/bin/spamfilter
# postfix reload

You can generate a config file from SA Configuration Generator. The output goes to /etc/mail/spamassassin/


user            = #SQL user
password        = #SQL password
hosts           = localhost
dbname          = # database name
query           = SELECT domain FROM domain WHERE domain=’%s’ and backupmx = ‘1’
user            = #SQL user
password        = #SQL password
hosts           = localhost
dbname          = # database name
query           = SELECT goto FROM alias WHERE address=’%s’ AND active = ‘1’
user            = #SQL user
password        = #SQL password
hosts           = localhost
dbname          = # database name
query           = SELECT domain FROM domain WHERE domain=’%s’
#optional query to use when relaying for backup MX
#query           = SELECT domain FROM domain WHERE domain=’%s’ AND backupmx = ‘0’ AND active = ‘1’
user            = #SQL user
password        = #SQL password
hosts           = localhost
dbname          = # database name

query           = SELECT quota FROM mailbox WHERE username=’%s’ AND active = ‘1’
user            = #SQL user
password        = #SQL password
hosts           = localhost
dbname          = # database name

#query          = SELECT CONCAT(domain,’/’,maildir) FROM mailbox WHERE username=’%s’ AND active = ‘1’
query           = SELECT maildir FROM mailbox WHERE username=’%s’ AND active = ‘1

4 thoughts on “Postfix, Dovecot, PostfixAdmin, Spamassassin on MySQL and CentOS 5.5

  1. Hi there.

    Thanks for this article.

    However, let’s say that postfix and dovecot were configured to be entirely separate except for postfix relying on dovecot to assist with SMTP AUTHs. Where would spamassassin fit in?

  2. Postfix and dovecot are separate. Dovecot is IMAP and POP3 server, postfix stores/processes the mail.

    Spamassassin is just an application that looks at a piece of mail and grades it. Nothing more, nothing less.

    Brian, sure. Will edit.

Leave a Reply

Your email address will not be published. Required fields are marked *