A Mail Server: Postfix, Courier, MySQL, SpamAssassin, Procmail, Maildrop, Postini


Setting up a mail server hasn’t been a simple affair. Fortunately, PickledOnion’s email tutorials gave me a jump start on configuring my Hardy slice as a mail server. After using Postfix and MySQL to get virtual mail delivery working, several offers for replica watches and discount meds reminded me that I needed junk filtering. Here I’ll detail the process that I went through to configure email handling on my slice.

Categorizing Mail with SpamAssassin #

At the time, SpamAssassin seemed like the best way to filter out junk. I’d heard of it before and configured SpamAssassin settings on shared hosting accounts at Hostgator and DigitalSpace. I’d used it and knew it worked; I just had to figure out how to set it up. I read a few warnings about SpamAssassin being a bit of a memory hog, but how bad could it be? I’ll come back to that later. It was easy enough to use aptitude install to download and install SpamAssassin, but it was elliot’s tutorial that helped me configure SpamAssassin and get it processing mail on my Ubuntu server.

I populated SpamAssassin’s whitelist and lowered the minimum SPAM score. Immediately SpamAssassin started doing a great job of telling me what was SPAM and what wasn’t. There were very few false positives, which were quickly remedied with more whitelisting.

The next problem was keeping SPAM from my inbox. SpamAssassin was doing a great job of categorizing SPAM, but I needed some way to avoid seeing the SPAM alongside my legitimate messages. Every new SPAM message to my inbox was an urgent reminder of two things:

  1. I needed to separate junk from real mail.
  2. With my own server, I just have to do everything!

Sorting with Procmail (or at least an attempt) #

Webmin, which has at times been extremely helpful and deserves its own post, had a menu item under SpamAssassin for Procmail delivery. It didn’t take much searching and reading to know that Procmail was just the filtering device that I was looking for. I installed Procmail and repeatedly configured /etc/procmailrc and restarted Postfix. Nothing ever happened. I made sure that my log file existed and had proper permissions. I checked my mail logs and found nothing helpful. I was still receiving mail that got filtered by SpamAssassin, but Procmail never did anything or logged anything. It was supposed to use SpamAssassin’s headers to determine whether the message was junk, and then either deliver to the inbox or to the Junk folder. Instead it did nothing.

Filtering with Maildrop #

My understanding of virtual delivery was lacking and I couldn’t get Procmail to work. It seemed like most of the example Procmail scripts I found assumed that you were using local delivery with real users (as opposed to virtual users like I was using via MySQL). I convinced myself that Procmail didn’t play nice with virtual delivery (wrong) and looked for alternatives. Despite looking for the wrong reason, I found Maildrop and eventually got that installed and filtering mail.

Here’s how I configured maildrop and got it working:

/etc/maildroprc

DEFAULT="$HOME/Maildir"
logfile "/var/log/maildrop.log"

SHELL="/bin/bash"
PATH=/bin:/usr/bin:/usr/local/bin:/usr/lib/courier/bin/
INBOX="/home/vmail/$DEFAULT"
DEFAULT="$INBOX"
SPAMFLD="$INBOX.Junk/"

# create the trash directory if it does not exist
`test -d "$SPAMFLD"`
if( $RETURNCODE == 1 )
{
`maildirmake "$SPAMFLD"`
}

# filter message through spamassassin's spamc agent
xfilter "/usr/bin/spamc -f"
if ( /^X-Spam-Status: Yes,/)
{
DELETE_THRESHOLD=9.0
/score=(\d+)/
if ($MATCH1 >= $DELETE_THRESHOLD)
{
to /dev/null
}
else
{
to "$SPAMFLD"
}
}

/etc/postfix/master.cf

maildrop  unix  -       n       n       -       -       pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}

/etc/postfix/main.cf

mailbox_command = /usr/bin/maildrop -d ${USER} ${RECIPIENT}
virtual_transport = maildrop

It’s imporant to note here that virtual_transport was critical because I was using virtual users and inboxes. The maildrop config lines in master.cf, combined with virtual_transport in main.cf seemed to be the key elements that allowed maildrop to filter mail.

Maxing Out the Slice #

Everything was finally working just like I wanted. The only minor detail was that my memory usage seemed high, and my virtual memory usage was — well — being used on occasion. Typically, I was running at about 230MB out of the available 256MB. In the Slicehost Campfire chatroom, I posted my memory usage statistics and promptly received some concerned feedback. My swap usage was over 100MB, which means that my memory usage was so high the system had to start dumping memory contents to the disk’s swap space. I was maxing out the 256MB of memory on my Slice, and I needed to tune some processes and avoid utilizing virtual memory.

I restricted my Apache limits a bit, knowing that none of my sites would generate heavy traffic. I reduced the number of SpamAssassin children running on the Slice. Both of these adjustments helped a bit, but my memory usage was still high. I restricted SSH, saslauthd, and Courier, but that proved to be pretty stupid. Mail.app would suffer from SSL errors and I’d get occasional authentication problems. I put those back quickly.

Weeks passed and I closely watched my memory usage. I didn’t want to sacrifice functionality, but my memory usage was high and occasionally pushed into swap territory; mostly as little as 80KB but sometimes up to 4-5MB. My top processes were Apache (which I couldn’t cut any further), SpamAssassin, and MySQL. Switching Apache for Lighttpd didn’t seem like a good idea for me. How could I cut down on my memory usage?

Filtering Mail with Google Apps/Postini #

I read a helpful post by unicks in Joyent’s forums (now gone from the internet) that explained how Google Apps/Postini offered an excellent mail filtering service that’s fairly easy to implement. I could still have complete control over the physical mail on my server, but with the benefit of up-to-date, state-of-the-art junk and virus filtering. Most importantly, I could drop SpamAssassin and save some memory.

All I had to do to configure this was to edit my DNS settings and point my MX servers to Postini. I then restricted Postfix’s allowed domains to Postini, so any mail that comes through my inbox has first passed through one of the more sophisticated SPAM filtering services on the market. The service will be less than $20/year, which is also a huge plus.

Regaining Memory #

Rather than paying to upgrade to a slice with more RAM, I’ve offloaded my SPAM filtering to Postini — which I trust more than myself to stay up-to-date and effective. My average physical memory usage now hovers at around 125MB, which is about 80MB less than my SpamAssassin setup took. My swap usage gets to about 80KB sometimes, but that doesn’t worry me too much.

* * *