Postfix MySQL howto v1.0

Last updated Februari 10 2013

Full-fledged Postfix using MySQL HOWTO

Postfix, MySQL, IMAP, WebMail, Virus- and spamscanning/checking mail system

by Tom Scholten and authors of likewise documents


Special thanks to Remco from WellnessAndConsultancy for testdriving this tutorial

Postfix logo_250x80



As my PostfixLDAP howto is getting agy and less used with a request from a fellow web-company and one of the main CT customers I’ve decided to write down a comprehensive guide on how to install a mailserver using Postfix based on MySQL – obviously with all the things I think you’ll need with that!

This howto will  – if succesfully deployed – give you an (FreeBSD) Postfix MySQL ViMbAdmin setup with Dovecot, RoundCube and MailScanner. Say what?

  • Postfix; main mailserver (as in SMTP, so for server traffic and sending mail)
  • MySQL; database
  • ViMbAdmin; web-gui to administer (or give someone partial rights) your mail-addresses
  • Dovecot; main mailserver (as in POP/IMAP, for fetching, storing your mail) including SIEVE (through pigeonhole) to have customer rule processing
  • RoundCube; webmail frontend
  • MailScanner + MailWatch; virus and spam-checks, the MailWatch is a front-end to which you can also have people de-quarantine their mail

Rules of engagement

This only describes how to build a mail-host on a secure, trusted, local network. We are not dealing with some of the things you should have in place first

  • working and active pf.conf
  • ssl-certificates for your web- and mail servers
  • (note that you DO need the ‘pem’ format for the mailservers in this document, revert to google and ‘cacert mailserver pem’ for more information
  • ensure your apache webserver has the certificates (or test-certificates) working and the production php.ini applied (see /usr/local/etc/php.ini-production)

We do not take any responsibility for your setup – this howto serves as a recipe on how you could do it. Read it and interpret it but create your own secure solution!

Documentation sources

FreeBSD 9.1 base install

install ‘plain’ (no lib32/games/doc) with ports
# freebsd-update fetch
# portsnap fetch
# cd /usr/ports/ports-mgmt/portmaster
# make install

Add to /etc/rc.conf


Edit /etc/make.conf

Prepare ports

Fetch the below /var/db/ports contents

Build the following

# portmaster mail/postfix databases/mysql55-server mail/roundcube mail/dovecot2 mail/dovecot2-pigeonhole www/apache22 lang/php5 lang/php5-extensions devel/git devel/subversion www/smarty3 www/zend-framework databases/pear-Doctrine12 ftp/wget shells/bash mail/mailscanner databases/p5-DBD-mysql

Note; do not build MailScanner with bdc!

Prepare database environment
# mysql -uroot

> use mysql;
> update user SET password=password(‘mastersecret0’) where user=‘root’;
> flush privileges;
> quit;

# mysql -uroot -p

> create database webmail;
> grant ALL ON webmail.* to ‘roundcube’@localhost IDENTIFIED by ‘secret0’;
> create database mailscanner;
> grant ALL ON mailscanner.* to ‘mailwatch’@localhost IDENTIFIED by ‘secrety’;
> grant file on *.* to mailwatch@localhost identified by ‘secrety’;
> create database postfixmail;
> grant ALL ON postfixmail.* to ‘vimbadmin’@localhost IDENTIFIED by ‘secret1’;
> grant SELECT ON postfixmail.* to ‘dovecot’@’localhost’ IDENTIFIED by ‘secret2’;
> grant SELECT ON postfixmail.* to ‘postfix’@’localhost’ IDENTIFIED by ‘secret3’;
> grant SELECT, RELOAD, LOCK TABLES ON *.* to ‘backup’@’localhost’ IDENTIFIED by ‘secret4’;
> flush privileges;
> quit;

# mkdir -p /home/vmail
# chmod 770 /home/vmail
# vi /etc/group
Add a group ‘vmail’ with id 2000
# useradd

> “vmail” as username
> “Virtual Mailbox” as description
> id 2000
> /home/vmail as directory
> group = vmail
> additional groups = mail
> nologin

# chown -R vmail:mail /home/vmail


# cp -pfr /usr/local/share/doc/dovecot/example-configs/* /usr/local/etc/dovecot/

Adjust according to


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

Add the contents of to

Create the mysql_ files as shown in

Add header_checks = regexp:/usr/local/etc/postfix/header_checks to
Create the file and have it contain
/^Received:/ HOLD


In /usr/local/etc/apache22/httpd.conf

  • Find the ‘DirectoryIndex’ declaration and add ‘index.php’ behind index.html (with a space separating them)
  • ‘untick’ the ‘vhost’ file inclusion near the bottom
  • add the following somewhere near there

# PHP settings
Include etc/apache22/extra/httpd-php.conf

Create an ./extra/httpd-php.conf containing
# This is the Apache server configuration file providing PHP support.
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

Create a file in ./Includes named ‘yourhost.conf’
<Virtualhost *:80>
DocumentRoot /usr/local/www/apache22/data/
Alias /vimbadmin /usr/local/vimbadmin/public

<Directory /usr/local/vimbadmin/public>

Options FollowSymLinks
AllowOverride None
Order allow,deny
allow from all
SetEnv APPLICATION_ENV production

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ – [NC,L]
RewriteRule ^.*$ /vimbadmin/index.php [NC,L]

# cd /usr/local/
# wget {url to latest version from}
# tar xfvz {file you got}

# ln -s {dir it created} vimbadmin

# cd /usr/local/vimbadmin
# cp application/configs/application.ini.dist application/configs/application.ini
# vi application/configs/application.ini

Set resources.frontController.params.displayExceptions = 0 to 1
Adjust ID’s to 2000
Adjust connection to
resources.doctrine.connection_string = “mysql://vimbadmin:supersecret@localhost/postfixmail”

DO NOT FORGET TO RESET displayExceptions back to 0 if vimbadmin GUI works!

Next switch to the /usr/local/vimbadmin/library directory and create symlinks
# ln -s /usr/local/share/pear/Doctrine Doctrine
# ln -s /usr/local/share/smarty3/ Smarty
# ln -s /usr/local/share/ZendFramework/library/Zend Zend

Now initialize the vimbadmin database
# cd /usr/local/vimbadmin
# bin/doctrine-cli.php create-tables

Putting it together

Start your webserver
# /usr/local/etc/rc.d/apache22 start

Browse to

Get the “salt” from this page

Put that in the application.ini file mentioned above + reset the displayExceptions to 0

Reload the page
Put in the salt
Put in a mailaddress en password

Congratulations, you can now login again 🙂

Now create a test-domain ( + mailbox (

Initiate a tail (-f) on /var/log/maillog
# /usr/local/etc/rc.d/dovecot start

Look for any errors and correct them (did you do your certificates!)

Check postfix config (warnings are OK-ish for now)
# postfix check
If all is well start postfix
# /usr/local/etc/rc.d/postfix start

Again, same thing (warnings are OK-ish for now)

Check resolving

# postmap -q mysql:/usr/local/etc/postfix/

Then start a telnet session to verify delivery

$ telnet localhost 25

you> ehlo host
you> mail from: johndoe
250 2.1.0 Ok
you> rcpt to: johndoe
you> rcpt to:
you> rcpt to:
250 2.1.5 Ok
you> data
354 End data with .
you> test
you> .
250 2.0.0 Ok: queued as 9729067C17
you> quit
221 2.0.0 Bye
Connection closed by foreign host.

Check your postfix/dovecot output in maillog for delivery

# ls -lR /home/mail/

There should be some mail in the maildir there 🙂

Congratulations you now have a working, basic, setup for your mailserver

Next up

Apache config for PHP
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# vi /usr/local/etc/php.ini
adjust error_log to /var/log/php.log
adjust date.timezone to ‘CET’
# touch /var/log/php.log
# chown www:www /var/log/php.log
Add php.log to /etc/newsyslog
Restart apache /usr/local/etc/rc.d/apache22 restart

MailScanner (and Postfix)

In /usr/local/etc/postfix add header_checks = regexp:/usr/local/etc/postfix/header_checks to
Create the file header_checks and have it contain
/^Received:/ HOLD

Next create Mailscanners’ directories
# mkdir -p /var/spool/MailScanner/incoming
# mkdir -p /var/spool/MailScanner/incoming/Locks
# mkdir -p /var/spool/MailScanner/quarantine
# mkdir -p /var/spool/mqueue
# mkdir -p /var/spool/

Getting ‘mailwatch’ from
# mkdir /tmp/src
# cd /tmp/src
# wget {url}
# tar xfvz {file from url}
# cd mailw*

*HINT* if the below command fails, replace “TYPE=MyISAM” with “Engine=MyISAM” through the create file and look for “timestamp(14)” and set this to “timestamp”
#mysql -umailwatch -p mailscanner < create.sql

#vi MailScanner_perl_scripts/

Edit the file for your database connections
# cp MailScanner_perl_scripts/ /usr/local/lib/MailScanner/MailScanner/CustomFunctions/
Create the admin user
#mysql mailscanner -u mailwatch -p
> INSERT INTO users SET username = ‘youruser’, password = md5(‘secret2much’), fullname = ‘Me Myself and I’, type =’A’
> \q

# mkdir {/wwwroot}/mailwatch
# cp -pfr mailscanner/* {/wwwroot}/mailwatch/
# cp {/wwwroot}/mailwatch/conf.php.example {/wwwroot}/mailwatch/conf.php
# vi {/wwwroot}/mailwatch/conf.php
Set your DB-user and Password & change below lines
define(‘MAILWATCH_HOME’, ‘{/wwwroot}/mailwatch’);
define(‘MS_CONFIG_DIR’, ‘/usr/local/etc/MailScanner/’);
define(‘MS_LIB_DIR’, ‘/usr/local/lib/MailScanner/’);
define(‘SA_RULES_DIR’, ‘/usr/local/share/spamassassin/’);

Edit /usr/local/etc/MailScanner/MailScanner.conf

  • Always Looked Up Last = &MailWatchLogging
  • Detailed Spam Report = yes
  • Quarantine Whole Message = yes
  • Quarantine Whole Message As Queue Files = no
  • Include Scores In SpamAssassin Report = yes
  • Quarantine User = root
  • Quarantine Group = apache (this should be the same group as your web server)
  • Quarantine Permissions = 0660
  • Incoming Work Permissions = 0640

Clean up
# rm -r /tmp/src/mailwatch*

Set groups
# vi /etc/group
Add “clamav” to the postfix group

Now add to your /etc/rc.conf


# /usr/local/etc/rc.d/clamav-freshclam start
{wait for a bit}
# /usr/local/etc/rc.d/clamav-clamd start
{make sure it’s succesfull, or wait some more and retry}
{If taking too long, run ‘freshclam’ and wait for it to download}
# /usr/local/etc/rc.d/mailscanner start
Watch for the output and try sending out a testmail to root – see if logging and processing work again

Add the following lines to your apache configuration, we’ve included the rules for vimbadmin just to be sure 🙂

<Virtualhost *:80>
  DocumentRoot /usr/local/www/apache22/data/
  Alias /vimbadmin /usr/local/vimbadmin/public
  <Directory /usr/local/vimbadmin/public>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    allow from all

    SetEnv APPLICATION_ENV production

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    RewriteRule ^.*$ /vimbadmin/index.php [NC,L]

  Alias /mailscanner /www/
  <Directory /www/>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    allow from all

  SetEnv APPLICATION_ENV production



Roundcube config

Before going live

Check firewall (pf.conf), and it’s activation
Install tripwire, monitoring and all that kind of stuff!


Tom Scholten is consultant with Snow B.V., a Dutch Technical Consultancy Company supplying specialists in the fields of Storage, Networking and Unix

Snow B.V. FreeBSD