Mail Server DIY

Building a proper mail server from scratch has always been something I wanted to do…but postponed because I felt the task to bee too daunting. I was wrong. Yes it cost me some weeks of effort, and a lot of trial and error, but the end result is something to be proud of.

No…this is not a step-by-step cook book on how to set up a proper mail server on Linux, with Postfix, Dovecot, MySQL, Roundcube, PostfixAdmin and Baikal. There are a lot of tutorials on the web. Some are good, others are…well…not so good. Since my mail server is build on Arch Linux (as are almost all of my servers and workstations, by now) the Arch Wiki “Virtual user mail system” was a good way to start. But beware: it’s not an “A to Z” tutorial, and it’s not for the novice. No tutorials are, but diving into the subject will at least broaden your knowledge of how mail servers function, and Linux in general.


I had been using Zimbra as my mail server for a couple of years, ever since I moved away from Windows. I was pretty content with it, simply because it worked with reasonable little effort to set up and knowledge of the underlying systems and processes. But it didn’t feel like I “owned” it. Also, I never liked the admin interface, and by replacing Zimbra with something new I could potentially also retire my last Ubuntu server.

Late December last year, an update to Zimbra failed, due to a bug on their side. That got me thinking (again), “maybe the time has come to replace Zimbra…”. I looked at a few “out of the box” alternatives, but none seemed right. I even tried to install iRedMail on a Arch server, but that didn’t work, and had it worked it would probably have spelled disaster in the future. No, it  was either going to be the “Virtual user mail system” from the Arch wiki, or submit defeat and stick to Zimbra

Well, it has been quite an interesting journey indeed. Sometimes frustrating, a lot of reverting back to earlier snapshots, but fortunately the end result is something to be proud of. The eventual shutdown of the Zimbra server turned out to be a bit premature, but the mail flow was up and running a day later, ans all was well. The at first seemingly hard task was done. Pat on my own back.

What I found


I lost a lot of time trying to get CalDav calendars (from Baikal) added to the Roundcube web mail client (which I absolutely love, by the way). Unfortunately, and quite unbelievable given the popularity of Roundcube, there are at the moment no viable calendar plugins with CalDav support. Apparently development of these (all forks from the only working calendar plugin by Kolab, which only connects to their proprietary server) has been nearly nonexistent for the last couple of years. A real shame, but I have good hope someone will pick up the challenge soon. It would make Roundcube even more awesome.

By the way: Thunderbird works flawlessly with Baikal‘s CalDav and CardDAV protocols. Use the new CardBook plugin in Thunderbird instead of the build in address book and the SoGo Connector plugin.

Mail location, don’t…

Hardly any tutorial I found mentions this, and I found out the hard way that it’s not a good idea to set the root of the (virtual user’s) mail folders identical to the (virtual) home. Why? You’ll find out once you start using quotas and sieves. Just don’t. Instead it’s much better to have a “mailbox” folder in the virtual home folders. This is easy to set up, fortunately.

In /etc/dovecot/dovecot.conf, make sure these settings are as follows. Of course you can choose to use another path instead of “/var/vmail/”, just be sure you do it consequently:

    mail_home = /var/vmail/%d/%n
    mail_location = maildir:/var/vmail/%d/%n/mailbox

In the file /etc/dovecot/dovecot-sql.conf you have created, the “Get the mailbox” SELECT statement must be (line truncated):

    user_query = SELECT ‘/var/vmail/%d/%n’ as home, ‘maildir:/var/vmail/%d/%n/mailbox’ as mail, ...

Finally, when we let PostfixAdmin create new users, we want it to create the proper mail location folder.  By adding the following lines of code to /etc/webapps/postfixadmin/, PostfixAdmin will do exactly that:

    $CONF[‘maildir_name_hook’] = ‘mailpath’;
    // maildir_name_hook custom function
    function mailpath($domain, $user) {
        $append = ‘mailbox’;
        $nameonly = substr($user, 0, strpos($user, ‘@’));
        return sprintf(“%s/%s/%s/”, $domain, $nameonly, $append);

Contrary to the Wiki, you don’t need LDA, just stick to the (newer) LMTP protocol, even when configuring quotas. Just make sure you have this in /etc/dovecot/dovecot.conf or /etc/dovecot/conf.d/20-lmtp.conf:

    service lmtp {
        unix_listener /var/spool/postfix/private/dovecot-lmtp {
            user = postfix
            group = postfix
        mode = 0600

This will create the LMTP listener socket, which is (simply put) the way Postfix “talks” to Dovecot. Most tutorials I found say that you must change the “virtual_transport” setting to “dovecot” in /etc/postfix/ That didn’t work for me, which (in hindsight) makes sense since I wasn’t using LDA but LMTP! This I found out just after going live and noticing that inbound mail was happily accepted by Postfix, but never actually reached the mailboxes 😮 After some panic and head scratching I found that I had to do this:

    virtual_transport = lmtp:unix:private/dovecot-lmtp

And presto! By the way, with LMTP there is no need to add the “dovecot” pipe in /etc/postfix/ at all.


Am I happy with this? You bet! Even the wife is happy, since Roundcube works much better for her than the Zimbra webmail client. Although I doubt she has even the faintest clue how much effort it took to get it all up and running 😉

Next time I’ll share the script I wrote to clean up folders and MySQL data, after removing mail users from PostfixAdmin.