Mail Setup

This is a major rewrite of my mail setup document. I’ve completely revamped the way I deal with spam and malware. If you are looking for my older document that includes descriptions of TMDA and Spfilter, you can find it here.


This document describes how mail moves around on the domain. It describes what software I use and how each piece is configured to get mail from point A to point B. It is intended to help anyone who is looking for some guidance in setting up their own mail system.

Some of the features of my mail system I’ll cover in this document include:

  • Selective relaying through my MTA
  • Webmail access to remote users
  • Virtual domains
  • Spam control


Before we get into the nitty-gritty of email delivery systems, I should go over the general environment all the software I’m about to describe operates in.

You will find an overview of the Arda Network, including a very nice diagram, here.

All mail accounts for the domain reside on Callisto and all are virtual, managed by a single system account. Mail received by and generated on Metis, Europa, Io, Thebe, Ganymede, and Leda is forwarded to Callisto for delivery.

Here is a diagram that details how mail routes through the Arda Network.

mail routing diagram

I’ve set up my mail server with the idea of being able to host multiple virtual domains for email accounts. People familiar with virtual domains will likely know about two very good packages designed to make virtual domains easier to use; vmailmgr and vpopmail.

I use neither of these packages in my setup, having opted for my own way of managing virtual domains. Because of my particular implementation, I don’t have access to many of the useful tools available in the two packages mentioned. This isn’t a big limitation for me because I need to deal with only a small number of virtual domains. For anyone contemplating setting up a mail server that will host a large number of virtual domains (I leave the interpretation of the word ‘large’ to the reader), I would recommend investigating either of the two packages mentioned.

Here is a list of the various software packages that I will be discussing in this document.

Software Installed On
Clamav 0.88.4 Thebe
Courier Authlib 0.58 Callisto
Courier IMAP 4.1.1 Callisto
Courierpassd 1.1.2 Callisto
Courierpasswd 1.1.2 Callisto
daemontools 0.76 Callisto
Fetchmail 6.3.4 Callisto
maildrop 2.0.1 Callisto
netqmail 1.05 Callisto
simscan 1.1 Callisto
SquirrelMail 1.4.6 Io
SpamAssassin 3.1.5 Callisto
ucspi-tcp 0.88 Callisto

The MTA (Mail Transfer Agent)

I use netqmail as my MTA for handling mail delivery for my domain. Netqmail is installed on all my machines save Ganymede. In this section, I will describe netqmail as it is installed on Callisto. See the section Netqmail as a Null Client for a description of netqmail installed on Europa. I also use the ucspi-tcp and daemontools packages to control and enhance the functionality of netqmail.

For those who don’t know, netqmail is stock qmail 1.03 distributed with a small number of patches and a script to apply them. You will find a link to netqmail in the Software Home Sites section. Since the differences between qmail and netqmail are really quite small, my commentary on netqmail applies equally well to qmail.

There are numerous MTAs available nowadays and you might be asking yourself why I chose netqmail over the others. My needs likely could be filled by any of the more common MTAs but there were a few considerations that made netqmail win out over the others.

I did a bit of research and found that netqmail was a little more mature than most of the more modern MTAs. I include Courier, Cyrus, Exim, and Postfix in this category. I also found numerous patches and add-ons to extend netqmail’s functionality. From this, it looked like netqmail was a stable, proven MTA that would have the features that I would need and that had a substantial developer community contributing to it. As it turns out, I am happy with the choice I made. Netqmail has done everything I’ve needed it to do so far and has not caused me any trouble.

In addition to the patches included with netqmail, I applied an additional patch to netqmail on Callisto. Here it is.

Patch Description
starttls-2way-auth-20060305.patch A composite patch that I maintain. It includes four patches that together provide secure SMTP communication using starttls, authenticated SMTP for both the server and client side of connections, and logging of canonicalised recipients by qmail-remote.

I applied this patch to netqmail after running the bundled script that applies the patches included with netqmail. I also commented out the line ‘#define CRAM_MD5′ in qmail-smtpd.c since Callisto doesn’t support CRAM authentication. After that, I built and installed netqmail following the netqmail documentation.

You can find a description of how I used to install qmail from the FreeBSD ports tree here

I applied the starttls-2way-auth patch for a few reasons:

  1. I wanted to use authentication between mail clients and qmail-smtpd to restrict who could relay mail through my mail server. This method seemed more flexible and reliable than using host-based filtering.
  2. Because usernames and passwords would be passed between mail clients and my server, I wanted to protect those passwords from network sniffers.

The starttls-2way-auth patch fills these needs. This patch requires some additional configuration of qmail over a stock installation and I’ll go into these differences where applicable.

It is also important to remember to disable CRAM type authentication in qmail-smtpd if you aren’t going to be using it. I didn’t at first and later found that qmail would advertise CRAM-MD5 authentication even though my mail server as configured doesn’t support it. This can confuse other programs that interact with qmail and cause them to fail authentication.

The starttls-2way-auth patch is a combination of the four following patches which can be found at

  • qmail-remote_authenticated_smtp
  • qmail-smtpd-auth-057
  • netqmail-1.05-tls-20060104
  • canonicalised-recipient-logging

While qmail-smtpd-auth-057 can be used to tell qmail-smtpd to require authentication before accepting mail, qmail-remote_authenticated_smtp can tell qmail-remote to use authentication when sending mail. I’m not using this later capability yet, but I thought I might, so I included it in my netqmail setup.

This patch can be found on the Arda Network qmail Downloads page.

Control Files

Here is the list of control files I use located in /var/qmail/control on Callisto.

Control File Contents
concurrencyincoming 40
databytes 10485760
defaultdelivery ./Maildir/
dh1024.pem —–BEGIN DH PARAMETERS—–
doublebounceto bitbucket
rsa512.pem —–BEGIN RSA PRIVATE KEY—–
servercert.pem —–BEGIN RSA PRIVATE KEY—–
tlsserverciphers HIGH:MEDIUM:!EXP:!ADH:+SSLv2:@STRENGTH

Some of these control files are worth explaining in more detail.

concurrencyincoming is not a standard qmail control file. It’s use is recommended by Life with Qmail. See the Run Scripts section for more details.
defaultdelivery is another control file recommended by Life with Qmail. It is also described in the Run Scripts section.
dh1024.pemdh512.pem, and rsa512.pem are three control files used by the starttls patch. They contain pre-computed Diffie-Hellman parameters in the first two control files and an RSA private key in the last one. Pre-computing these values speeds up starttls transactions a lot, especially ones that use Diffie-Hellman parameters. These values are changed periodically by calling update_tmprsadh from a cron job. The update_tmprsadh script is included in the starttls patch. Better yet, the patch includes documentation on how to use it.
servercert.pem is also part of the starttls patch. It allows connections to and from qmail-smtpd to be made using SSL. Since I’m using authentication to restrict who can send mail through my server, passwords are traveling between mail clients and my server every time someone sends mail. This way, passwords are protected against network sniffing attacks.
The smtproutes file points at my ISP’s SMTP server causing all mail leaving my domain to be routed through this server. I do this because a significant number of mail servers in the wild will refuse mail coming from a server that fails a reverse DNS lookup. Also, an increasing number of ISPs reject mail coming from dynamically assigned IPs as an anti-spam measure. Since I have a dynamic IP, passing my mail through my ISP presents the world with a nice, statically IPed, mail server to talk to.
The tlsserverciphers file is also part of the starttls patch. I’m using it to make sure SMTP clients don’t connect to my mail server using export grade algorithms (no keys less than 128 bits are allowed). If you have OpenSSL installed on your system, then ‘man ciphers’ will explain the contents of this file for you.
You’ll notice that I have no locals control file. That’s because I’ve set up the domains that I accept mail for as virtual domains which are listed in the virtualdomains file. Why did I set things up this way? I did it this way partly as an exercise but also because I liked the idea of keeping mail accounts out of my /etc/passwd file. A more usual configuration would have a single local domain servicing system administrators for example plus one or more virtual domains for mail users who don’t need login rights on the server. My network is pretty small, so I put everything in virtual domains. The fact that I have no local domain also forced me to set up aliases to standard mail recipients like root and mailer-daemon a little differently than what you’d normally expect. I’ll get to the details in the next section.

Whereas most of the control files are owned by root:qmail with permissions set to 644, the dh1024.pem, dh512.pem, rsa512.pem, and servercert.pem control files are owned by qmaild:qmail with permissions set to 600. This is to preserve the security of the Diffie-Hellman parameters and private keys used by qmail.

The vmail System Account

vmail is the system account whose sole purpose is to handle the mail accounts of all virtual domains set up on my server. The breathtakingly original name vmail was an arbitrary decision, the system account can be named anything you want. Mailboxes of all mail users are located in subdirectories in vmail’s home directory. A sample listing of vmail’s home directory looks like this:

-rw-------  1 vmail    vmail     230 Mar 26  2003 .fetchmailrc
-rw-------  1 vmail    vmail     652 Jan 24 21:50 .mailfilter
-rw-r--r--  1 vmail    vmail     166 Jan 24 21:44 .qmail
lrwxr-xr-x  1 vmail    vmail       6 May  4  2003 .qmail-default -> .qmail
drwxr-xr-x  3 vmail    vmail     512 Apr 20 23:37 abuse
drwxr-xr-x  3 vmail    vmail     512 Apr 16  2003 arda-homelinux-net
drwxr-xr-x  9 vmail    vmail     512 Aug  7 18:31 arda-homeunix-net
-rw-r--r--  1 root     vmail     126 Dec 26 11:38 bayes-ham-folders
-rw-r--r--  1 root     vmail     130 Dec 26 11:39 bayes-spam-folders
-rwxr--r--  1 root     vmail     356 Dec 27 09:31 bayes-teach

Here you can see the .qmail files for the vmail account. For a further explanation of the .qmail files see the next section. The .mailfilter file is used by maildrop; see the Local Mail Delivery section for more information. The bayes-* files are explained in my SpamAssassin Setup document. When using virtual domains, it is common practice to place all the mail accounts for a particular domain within a directory named after the domain. This is what I’ve done here. I have two virtual domains listed here, arda-homelinux-net and arda-homeunix-net, which correspond to the domains in qmail’s control files listed in the previous section. Here is a sample of what one of these directories looks like.

drwx------   8 vmail  vmail   512 Feb 13 23:06 andrew
drwx------  10 vmail  vmail   512 Feb 13 23:06 johanne

Each mail account has its own subdirectory within the domain directory. Giving each mail account its own subdirectory was convenient because it gave me somewhere to put account specific configuration files. It also helps to keep the mail accounts organized.

.qmail Files

On my systems, .qmail files are used to control the local delivery of mail. vmail’s home directory contains only the .qmail files directly related to the vmail system account. All .qmail files associated with virtual mail accounts reside in the subdirectory of that mail account. For example, .qmail files used by reside in /home/vmail/arda-homeunix-net/johanne. Each mail user gets two .qmail files that follow this basic pattern:

File Name Contents
.qmail |preline /usr/local/bin/maildrop .mailfilter
.qmail-default none – link to .qmail

As you can see, the .qmail file simply calls maildrop, the Mail Delivery Agent (MDA) that I use. Maildrop does all the real work of delivering email locally like applying special filters and specifying the Maildir directory for the mail account. You can find a description of how I use maildrop in the Local Mail Delivery section.

The .qmail-default file ensures that mail will be delivered properly if users add extentions to their regular email addresses.

In addition to .qmail files for each mail account, vmail also gets two .qmail files that follow the same pattern as described above. The purpose of vmail’s .qmail files is a little different from those of user accounts. vmail’s .qmail files look like this:

File Name Contents
.qmail |preline /usr/local/bin/maildrop .mailfilter
.qmail-default none – link to .qmail

The first .qmail file is not likely to receive any mail directly as that would mean the mail was addressed to vmail which shouldn’t happen. The second file is what makes the first file work. The second file catches all mail addressed to an account not supplied with its own home directory and .qmail files. Therefore, mail addressed to would be caught by the .qmail file in andrew’s mail account subdirectory while mail addressed to would be caught by the .qmail-default file in vmail’s home directory. It would then be handled according to the rules in vmail’s .qmail file. How qmail finds the proper mail account subdirectory of legitimate mail users is explained in the User Database section of this document.

The above explanation seems to imply that I don’t, in fact, need vmail’s .qmail file at all and could make due with just the .qmail-default file. That is probably true. However, all of the mail accounts use the two .qmail files and so I set up vmail the same way for consistency’s sake.

You’ll notice that, like user mail accounts, vmail uses maildrop to deliver incoming mail. This is what allows me to reject mail addressed to non-existant users on my domains but still receive mail to specific system aliases that don’t have .qmail files of their own. A more thorough explanation of this can be found in the sections dealing with aliases and the user database as well as the section on Local Mail Delivery.

System Aliases

In a typical netqmail installation, the system aliases are configured by adding files to netqmail’s alias directory. In the context of my mail server, I was interested in setting up the following system aliases:


Each alias gets a file in the alias directory telling qmail who should receive mail addressed to that alias, typically the mailbox of some overworked sysadmin. This setup does not work on my installation however.

Because I’m using virtual domains with my system aliases, the recipient of all incoming mail is rewritten to the form <domain-name>-<recipient>. For example, mail received for will actually be delivered by qmail to arda-homeunix-net-postmaster. This confuses the alias directory no end and means that aliases for postmaster, or even arda-homeunix-net-postmaster, don’t work. This is the reason I had for setting up the .qmail and .qmail-default files in vmail’s home directory described in the previous section.

The User Database

The qmail user database is normally used to map qmail usernames to system usernames and can also be used to set up user aliases. The database lives in the /var/qmail/users/assign file. The assign file can be converted into a cdb format database using the qmail-newu program. Again, because I’m using virtual domains controlled by one system account, my user database is set up a little differently.

I’m using the user database to do two things. One is to map my system account to my mail account. I’m doing this because I have some cron jobs that mail error reports to my system account and I want to pick up these reports in my virtual mail account. The second job the user database is doing is to tell qmail where to look for the .qmail files associated with mail user accounts. This is how qmail knows to look in /home/vmail/arda-homeunix-net/johanne for instructions on how to deliver mail to johanne’s inbox for example.

This is what my assign file looks like.


All mail users get two lines in the assign file, one starting with a ‘+’ sign and the other starting with a ‘=’ sign. The ‘+’ at the beginning of the line indicates a wildcard match allowing extended addresses to be delivered correctly. Mail addressed to andrew-mailinglist would be delivered to andrew for example. The ‘=’ sign indicates that an exact match to the mail address is required. Together, these two lines allow a mail user to receive mail using extended addresses while reducing the possibility of delivering mail to the wrong account; mail addressed to jonathan will not be delivered to jon for example.

The first two lines of the file don’t refer to regular mail users. The first line directs mail addressed to my system account (the account I use to log into my various machines) to my virtual mail account. The second line tells qmail where to find .qmail files for mail retrieved from my mail account on my ISP’s mail server. See the section Retrieving Mail from my ISP for more details. Notice that both these lines begin with a ‘=’. This means that both require exact matches, no address extentions are allowed.

The last entry in the assign file is special. It is a catch-all line that directs mail not caught by a more specific entry to vmail’s home directory. Remember that this is where mail addressed to the system aliases will go and where I handle mail addressed to non-existant users. Notice that the last line of this file is a period. Don’t forget this period or the user database won’t work.

Some of you may have realized that I could have put all my system aliases into the user database and eliminated the need to use .qmail files in vmail’s home directory for delivering mail to these addresses. For example, I could put the line:


into the assign file which would be sufficient to deliver mail for postmaster to my mail account. As is apparent from this example, however, I would need a separate entry for every virtual domain for which I wished to receive mail addressed to postmaster. With many domains, this would quickly become tedious and lead to a cluttered user database.

I used to have qmail set up so that all .qmail files resided in vmail’s home directory. Setting up the user database as described has allowed me to move most .qmail files out of vmail’s home directory and into the subdirectories of the mail accounts they pertain to. This has gone a long way to making my mail system more manageable as having all those .qmail files in one directory was making vmail’s home very crowded.

Run Scripts

Two scripts are used to start qmail, qmail-send which handles delivering mail to local accounts and for sending it to remote servers, and qmail-smtpd which handles receiving mail from other mail servers and from mail clients that can talk SMTP. We’ll look at each of my run scripts in turn.

My qmail-send run script looks like this:



# Using qmail-local to deliver messages to ~/Maildir/ by default.

DEFAULTDELIVERY=`cat /var/qmail/control/defaultdelivery`

exec env - PATH="/var/qmail/bin:$PATH" \
qmail-start "$DEFAULTDELIVERY"

It’s pretty simple. It sets up the needed PATH environment variable and sets the default delivery location for mail intended for local mail accounts. The defaultdelivery control file is not standard to qmail but its use is recommended by Life with Qmail. The default delivery location is not normally used as the .qmail files in each user’s subdirectory will be consulted by netqmail to determine delivery instructions. If I forget to put a .qmail file in someone’s directory or if the file gets deleted, however, the default location acts as a safety net for mail delivery. If you don’t specify a delivery location, qmail-send defaults to ~/Mailbox.

My qmail-smtpd run script is rather more complicated. It looks like this:



QMAILUID=`/usr/bin/id -u qmaild`
COURIERGID=`/usr/bin/id -g courier`
MAXSMTPD=`/usr/bin/head -1 /var/qmail/control/concurrencyincoming`
LOCAL=`/usr/bin/head -1 /var/qmail/control/me`

# set the maximum number of processes to 64. default was 40.
ulimit -u 64

if [ -z "$QMAILUID" -o -z "$COURIERGID" -o -z "$MAXSMTPD" -o -z "$LOCAL" ]; then
    echo /var/qmail/supervise/qmail-smtpd/run
    exit 1

if [ ! -f /var/qmail/control/rcpthosts ]; then
    echo "No /var/qmail/control/rcpthosts!"
    echo "Refusing to start SMTP listener because it will create an open relay"
    exit 1

# using tcpserver to control the behaviour of qmail's smtp server

exec /usr/local/bin/softlimit -m 4000000 \
/usr/local/bin/tcpserver -v -R -l "$LOCAL" -x /usr/local/etc/tcprules.d/tcp.smtp.cdb \
-X -c "$MAXSMTPD" -u "$QMAILUID" -g "$COURIERGID" 0 smtp \
/var/qmail/bin/qmail-smtpd /usr/local/sbin/courierpasswd -s imap -- /usr/bin/true 2>&1

Like the qmail-send run script above, I modeled this run script after the one found in Life with Qmail. Like defaultdelivery, concurrencyincoming is not a standard qmail control file but is something added by Life with Qmail. Softlimit is part of the daemontools package while tcpserver is from the ucspi-tcp package. I’m using softlimit to cap the memory usage of qmail-smtpd. Tcpserver acts as a super-server and is intended to replace other super-servers such as inetd and xinetd.

Two things are of particular note with this run script, the tcp.smtp.cdb database and courierpasswd.

The -x option directs tcpserver to filter incoming SMTP connections using a database; tcp.smtp.cdb in this case. This database is pretty simple on my system. Here it is.


The first line sets the default policy to deny. Unless a more specific line overrides it, a connection to tcpserver will be denied.

The second line specifies Thebe’s VPN IP. All mail from outside my local network will arrive on this IP. The QMAILQUEUE environment variable tell’s qmail-smtpd to send mail arriving from Thebe to simscan instead of to qmail-queue so that it can be scanned by SpamAssassin. See the Stopping Spam & Malware section and my SpamAssassin Setup document for more details.

The third and forth lines tell tcpserver to accept connections from localhost and my local network. This lets local users send email to Callisto. Notice that the RELAYCLIENT environment variable is not set in either case. Without some other mechanism in place, local users cannot send mail to domains not hosted by my server. That brings us to the second point of note in my run script.

The program invoked by qmail-smtpd, courierpasswd, authenticates users who try to send mail through my server to a remote domain. This is how I prevent my mail server from being used as an open relay. Courierpasswd accesses user account information through courier-authlib, the Courier authentication library. Not surprisingly, the authentication library is how Courier IMAP looks up account information too. Using courierpasswd allows me to use a common method to retrieve account information so that I never have to worry about qmail and Courier IMAP getting out of sync. I have to set tcpserver’s gid to ‘courier’ so that courierpasswd can communicate with courier-authlib properly. One consequence of using an authentication program with qmail-smtpd is that no one can relay mail through my mail server unless they use a mail client that supports SMTP authentication.

One reason I like using courierpasswd so much is because I wrote it. You can find it here.

netqmail as a Null Client

In addition to providing mail services to the outside world, I also want to receive mail from other machines on my network. For the most part, these consist of automated mailings from root providing status information on the machines. In order to receive this mail in my account on Callisto, I needed to set up qmail on the other machines on my network as well. So, by null client, I mean using qmail to send mail generated locally to a designated mail server but to not accept any mail from other machines nor to deliver mail locally. As an example, I’ll describe how qmail is set up on Europa, my DNS and DHCP server. You’ll recall that Europa is running Mandrake Linux as the operating system.

Things I didn’t have to worry about on Europa were aliases, a user database, dot files, or virtual mail users. None of these items are necessary to run qmail as a null client. This really only left control files and a startup script to deal with.

Control Files

Here is the list of control files I use located in /var/qmail/control on Europa.

Control File Contents
locals #

You’ll notice that there are fewer control files on Europa as compared to Callisto. Of particular note is the absence of a virtualdomains file. Also, the smtproutes file points to instead of my ISP’s SMTP server as it does on Callisto. is an alias I’ve set up in my DNS server to point to Callisto. Some time ago I had occasion to change which of my machines was acting as the mail server and using an alias made the switch less complicated.

The rcpthosts control file is also missing. But don’t panic. Europa isn’t an open relay and can’t be one because it isn’t running qmail-smtpd at all. We’ll get to that when I discuss my run scripts.

One control file that is here is the locals file. But I said that Europa doesn’t deliver any mail locally. The only thing in the locals control file is a single hash ‘#’ sign. This prevents netqmail from attempting local mail delivery. Without it, netqmail will delivery an email locally if it is addressed to <local> where <local> is a valid username with a home directory on Europa.

Run Scripts

Because Europa doesn’t accept mail from other machines, I don’t need a qmail-smtpd run script. I do have a qmail-send script on Europa. Here it is.


# Using stdout for logging

exec env - PATH="/var/qmail/bin:$PATH" qmail-start

This script starts up the processes necessary to send mail to Callisto. It also starts up processes used to deliver mail locally. These processes aren’t necessary as no mail is delivered locally but they don’t harm anything for being there. As with Callisto, I use programs from the daemontools package to control the qmail-send run script. Unlike Callisto, here I don’t use a defaultdelivery control file since no mail is delivered locally.

Local Mail Delivery

Local mail delivery on Callisto is handled by a Mail Delivery Agent or MDA. An MDA acts as a bridge between the MTA (netqmail in my case) and a user’s inbox. MDAs are often used to filter incoming mail in order to direct it to specific mail folders or to forward mail to an alternate address.

I use maildrop as my MDA. Another popular MDA is procmail. When it came time for me to choose an MDA, I looked at both maildrop and procmail. I decided to use maildrop for the simple reason that I found it easier to understand maildrop’s configuration syntax. From what I’ve read, both programs overlap quite a bit in their functionality. Which one you choose will depend heavily on personal preference and past experience.

I invoke maildrop at local delivery time through .qmail files. To refresh your memory, here is a typical .qmail file from one of the mail accounts on Callisto.

|preline /usr/local/bin/maildrop .mailfilter

The .qmail file invokes maildrop by specifying a .mailfilter file found in the account’s home directory.

Here is what the .mailfilter file looks like.

import SENDER


#logfile "/home/vmail/maildrop.log"

# If Spamassassin says the mail is spam, put it in the Spam folder.
if ( /^X-Spam-Status: *Yes/)
        `test -d ./Maildir/.Spam`
        if( $RETURNCODE == 1 )
                `/usr/local/bin/maildirmake -f "Spam" ./Maildir`
                `/usr/local/sbin/subscribeIMAP "Spam" "$HOME"`

        to "Maildir/.Spam"

to Maildir

This .mailfilter file is really only doing one thing. It checks to see if the mail has been identified as spam by SpamAssassin and, if so, delivers the mail to the user’s ‘Spam’ folder. If the email is determined not to be spam, then it is delivered to the user’s inbox.

For more details on how I use SpamAssassin, see my SpamAssassin Setup document.

The .mailfilter file used by vmail is a little different from that of normal mail user accounts. Here it is.

import SENDER

#logfile "/home/vmail/vmaildrop.log"

# bounces to bitbucket are dropped
if ("$RECIPIENT" =~ /-bitbucket@arda\.homeunix\.net/)

# accept messages to root, postmaster, webmaster, and mailer-daemon
# and accept bounce messages
if ("$RECIPIENT" =~ /-root@/ || \
    "$RECIPIENT" =~ /-postmaster@/ || \
    "$RECIPIENT" =~ /-webmaster@/ || \
    "$RECIPIENT" =~ /-mailer-daemon@/ || \
    "$SENDER" =~ /<>/)
        to "!andrew"

# accept messages to abuse at any domain I host. All such messages
# go to the same abuse account
if ("$RECIPIENT" =~ /abuse@/)
  # Put spam in the Spam folder and ham in the Ham folder
  # of the abuse account.
  if ( /^Subject: \[SPAM: /)
    # Pull the attachment out of the message.
    exception {
      xfilter '/usr/local/bin/reformime -s 1.2 -e'

    `test -d ./Maildir/.Spam`
    if( $RETURNCODE == 1 )
      `/usr/local/bin/maildirmake -f Spam ./abuse/Maildir`

    to "abuse/Maildir/.Spam"
  if ( /^Subject: \[HAM: /)
    # Pull the attachment out of the message.
    exception {
      xfilter '/usr/local/bin/reformime -s 1.2 -e'

    `test -d ./Maildir/.Ham`
    if( $RETURNCODE == 1 )
      `/usr/local/bin/maildirmake -f Ham ./abuse/Maildir`
    to "abuse/Maildir/.Ham"

  to "abuse/Maildir"

# Bounce messages to all other mail accounts.
# Entries in the qmail users database should
# catch mail to valid user accounts before this
# filter file is invoked.
echo "Sorry, no mailbox here by that name. (#5.1.1)"

The first thing this .mailfilter file is doing is dropping any email addressed to This is the address that qmail delivers double bounces to. Since nowadays the vast majority of double bounces are generated by spam with forged From headers, I’ve decided to just discard them.

The next thing the file is doing is handling email sent to certain generic addresses that I want to accept. I’ve set up the filter patterns the way that I did because of the particular way I’m using virtual accounts in my qmail setup. This .mailfilter file will match the generic addresses for any of the domains hosted by my server and forward the mail to my account. The file is also forwarding bounce messages to my account.

A good portion of the file is dedicated to handling email sent to the abuse account. I use a SquirrelMail plugin that allows users to identify mail as spam or ham, and send it to my abuse account where it will be used to train SpamAssassin’s Bayesian filter. How this works is detailed in my SpamAssassin Setup document.

The last thing being done by the .mailfilter file is to bounce any message addressed to an account not already handled by the file. As the comment in the file states, email addressed to legitimate user accounts should have been directed to the appropriate .qmail file by qmail’s users database. If a message makes it to the end of vmail’s .mailfilter file, that means the account doesn’t exist on my server and the message needs to be bounced. Since I started using the Recipients patch on Thebe that checks the recipients on incoming mail to see if they really exist on my system, no emails have made it this far through the .mailfilter file.

The IMAP Server

I use Courier as my IMAP server. I originally used UW-IMAP but I wanted something that would support Maildir format mailboxes natively as well as a more flexible authentication mechanism than what UW-IMAP provided.

I wished to use virtual accounts for all the mail users on Callisto and Courier provides a number of ways to do this. I opted to use the userdb option since there is very good documentation on the Courier IMAP web site on how to do this and because I don’t have enough accounts to warrent using LDAP or an SQL database. You probably already know that the IMAP server portion of Courier is available as a package separate from the full mail server package. I use the IMAP server package and this should be kept in mind while reading the following description. I will often refer to my setup as ‘Courier’ rather than ‘Courier-IMAP’ simply to save keystrokes. Where I make reference to the full Courier package, I will make this clear.

The authentication mechanism used by Courier-IMAP is contained within a separate package, Courier-Authlib. Courier-IMAP will not install unless Courier-Authlib is installed first.

Configuration Options

I built Courier-Authlib and Courier-IMAP from the FreeBSD ports tree. Courier-IMAP is found in /usr/ports/mail/courier-imap but Courier-Authlib is split into many ports. The one you choose to install depends on which authentication module(s) you want to use. I installed /usr/ports/databases/courier-authlib-usergdbm to get the userdb functionality.

I set these environment variables when building Courier-IMAP.

  • WITH_FAM=true
  • WITH_GDBM=true

Mail Accounts

Here is a sample of what my userdb file looks like:

vmail   uid=1000|gid=1000|home=/home/vmail|shell=/bin/sh|systempw=*|gecos=Virtual Mail User
1000=   vmail
andrew  imappw=<password hash>|uid=1000|mail=/home/vmail/arda-homeunix-net/andrew/Maildir|home=/home/vmail/arda-homeunix-net/andrew/|gid=1000
dhahn107 imappw=<password hash>|uid=1000|mail=/home/vmail/arda-homeunix-net/david/Maildir|home=/home/vmail/arda-homeunix-net/david/|gid=1000

It shows the entries for the vmail system account as well as two entries for mail accounts. Vmail is the only account that gets two entries in the userdb file. andrew and dhahn107 represent typical mail user accounts.

You will notice that the entries for andrew and dhahn107 use imappw to identify the user’s password. This provides a way for Courier to restrict what a particular password can be used for. Other possible values are ‘poppw’ and ‘systempw’. It is because I’m using imappw here that I need to include the -s switch with courierpasswd and courierpassd.

One account, dhahn107, bears considering in more detail. Because it is so often the case that the user id of an email account matches the local part of the user’s email address (the part before the ‘@’ sign) it is easy to forget that the two don’t have to be the same. When using multiple virtual domains, having the two always the same would impose an undesirable limitation. If the two were always the same, it would mean that I could not have the two accounts and on my mail server; it would be ambiguous which ‘david’ account I was sending mail to or from. With the user id different from the email address, I can have a ‘david’ account in each of my hosted virtual domains. Note that I still cannot have two ‘david’ accounts within the same virtual domain.

So why then do I have the user id andrew in my userdb file instead of something like asjahn001 you ask? Because I’m the sysadmin, and I make the rules.

It may be useful to note that the mail account user id appears nowhere else in my server setup. The only other place the user id will be used is by the user when logging into my server with his or her mail client.

Configuration Files

In my installation, I use the following three configuration files.


authmodulelist="authuserdb authpam"
authmodulelistorig=" authuserdb authvchkpw authpam authldap authmysql authpgsql"

This file is pretty staightforward. You will notice that the authmodulelist has two authentication modules listed, authuserdb and authpam. All my mail accounts are set up in the userdb file so I don’t really need the authpam module there. I find it useful to test authentication against system accounts from time to time, however, which is why I haven’t removed it. The authdaemonvar parameter tells you where the domain socket lives that’s used to communicate with the installed authentication modules. Courierpassd and courierpasswd need to be able to connect to this socket to function properly.


TCPDOPTS="-nodnslookup -noidentlookup"

Apart from setting IMAPDSTART to yes, the only options I changed from their default values were IMAP_ENHANCEDIDLE, IMAP_MOVE_EXPUNGE_TO_TRASH, and MAXPERIP. The first option allows two mail clients connected to the same account have changes made by the first client show up in the second. This is a very useful feature if you use shared mail folders. I changed the second option simply as a safeguard in case I delete a message I really want. I can always go looking for it in the Trash folder. I needed to change the MAXPERIP option because of a problem I was encountering with the default value of 4 when used with Netscape. Netscape likes to spawn new connections to the IMAP server whenever you open a new mail folder. This soon exhausted the maximum of 4 connections and Netscape would refuse to read any more folders until I had disconnected from the server and reconnected. The value of 12 I’m using now was chosen completely arbitrarily. All I can say is that I’ve had no problems since changing the value. You may need to fiddle with this depending on how many folders are in your mail account. If you have a webmail system that connects to Courier and you have lots of users accessing their accounts at the same time, you may need to use a larger value.



ere was where Courier looks for my server certificate. It’s the same certificate that netqmail uses to establish secure connections.

Starting Courier

I use two init scripts, and, to start Courier-Authlib and Courier-IMAP respectively. The two ports installed these init scripts in /usr/local/etc/rc.d and all I had to do to activate them was to add these two lines to my /etc/rc.conf file.


Courier-IMAP installs three additional init scripts for starting the POP server and starting the IMAP server on port 143. Since all I want is the IMAP server listening on port 993 (the imaps port), I don’t use these three init scripts.

The Webmail Interface

I use SquirrelMail to access virtual mail accounts through the web. Why SquirrelMail you ask? Because it was the first webmail package that I was able to successfully install is the short answer. Part of this may be because it required less supporting software to get it to work than other webmail packages I investigated. I was also looking specifically for IMAP support and didn’t mind that SquirrelMail does not do POP. It turned out to be a good choice as I’m quite happy with it. SquirrelMail offers quite a bit of flexibility in the IMAP servers it supports and in the many plugins written for it which allow you to pick and choose the functionality you want.

There really isn’t much to say about my SquirrelMail setup. I installed the software on Io, told it to use Courier as the IMAP server, told it that my SMTP server requires authentication and it worked. You can’t argue with results like that. One aspect of my SquirrelMail configuration that is peculiar to my setup is that I have SquirrelMail pointing to localhost for SMTP service with the smtp port set to 465. My configuration is set up this way because I’m using Stunnel to secure the SMTP connection between SquirrelMail and Callisto. See courierpassd in the section Daemontools on Callisto and my Stunnel Setup document for more details. Here is a useful screenshot of my Squirrelmail server settings as viewed using

1.  Domain                 :
2.  Invert Time            : false
3.  Sendmail or SMTP       : SMTP

IMAP Settings
4.  IMAP Server            :
5.  IMAP Port              : 993
6.  Authentication type    : login
7.  Secure IMAP (TLS)      : true
8.  Server software        : courier
9.  Delimiter              : detect

SMTP Settings
4.   SMTP Server           : localhost
5.   SMTP Port             : 465
6.   POP before SMTP       : false
7.   SMTP Authentication   : login
8.   Secure SMTP (TLS)     : false
9.   Header encryption key :

Because SquirrelMail is written in php, I needed to ensure certain parameters were set properly in my php.ini file. The settings that are relevant to SquirrelMail follow. I needed to modify the include_path parameter because I’m running PHP in safe mode.

      file_uploads = On
      register_globals = Off
      session.auto_start = 1
      session.save_path = /var/php-sessions
      session.use_cookies = 1
      upload_max_filesize = 10M
    include_path = “.:/php/includes:/usr/local/share/pear”

The /var/php-sessions directory is owned by the user that my web server runs as. It’s permissions look like this.

drwxr-x--- 2 www www 512 Nov 9 18:55 /var/php-sessions

By the way, I’m using php version 5.1.6 built as an Apache module.

As I mentioned previously, one of the nice things about SquirrelMail is the ability to extend its capabilities with the numerous plugins available for it. Here is the list of plugins I have working with my installation.

Name Version
abook_take core
attachment_tnef 0.7
calendar core
change_pass 2.7
compatibility 2.0.4
compose_chars 0.1
folder_sizes 1.4
image_buttons 1.4
message_details core
password_forget 2.1
quicksave 2.3
select_range 3.5
spam_buttons 1.0
squirrel_logger 2.0
squirrelspell core
timeout_user 1.1.1
user_special_mailboxes 0.1
view_as_html 3.7a
vkeyboard 0.8.1

The plugins with version numbers of ‘core’ are included in the SquirrelMail distribution.

One of the plugins listed in the above table is change_pass. As you may have guessed, this plugin provides mail users the ability to change their account password. Given that all mail accounts on Callisto are virtual, providing a means for users to change their password seemed like a good idea to me.

The change_pass plugin uses one of two programs (poppassd or courierpassd) to change the password of users. Both use the same network protocol to talk to clients making the two programs interchangable. Which program you choose to use depends on how you want to authenticate mail users. Poppassd uses PAM to change passwords. Since I use Courier as my IMAP server, I’m using the courierpassd program which uses configured Courier authentication modules to change passwords. Its use allows SquirrelMail to access Courier’s user database even though Courier is installed on a different machine from my web server. Another reason I’m using courierpassd is because I wrote it.

The big downside of using courierpassd in this way is that the connection between server and client is insecure, plain text user IDs and passwords are flying around the network when using this program. I’ve overcome this drawback by using Stunnel to secure the connection between SquirrelMail and my mail server.

Some of you familiar with Squirrelmail may be aware that Squirrelmail provides the option to use TLS secured connections between it and the SMTP server it talks to. Why aren’t I using SquirrelMail’s native TLS support? After all, I use it for IMAP communication. It has to do with the fact the SquirrelMail doesn’t do STARTTLS, only SMTPS. See my Stunnel Setup document for more details.

Retrieving Mail from my ISP

In addition to the mail accounts I have set up on my own mail server, I still have an email account with my ISP that I just haven’t been able to ween myself away from. Rather than have mail in two different locations, I decided it would be nice to be able to automatically download mail from this account into an account on my own mail server. Another reason to do this is because I get spammed on this account from time to time. Rather than pay my ISP to apply their anti-spam measures to my account, I’d rather download the messages to my server and use my own spam-stopping tools. This is what I’m using Fetchmail to accomplish.

Fetchmail really is a gem of a program. My simple setup doesn’t do justice to its capabilities. If anyone needs a program to take mail from one or more mail accounts and deliver it to accounts on one or more other mail servers, you should take a look at Fetchmail. You’ll be glad you did.

Since my ISP mail account doesn’t see a lot of volume, I’m running Fetchmail twice a day from a cron job to check for mail on my ISP’s mail server and download it to Callisto. Here is what the cron job in /etc/crontab looks like.

# check my ISP mail account twice a day
24 5,18 * * * vmail /usr/local/bin/fetchmail --silent -f /home/vmail/.fetchmailrc

Fetchmail runs as vmail, the system account I use to control virtual mail accounts on Callisto. Fetchmail doesn’t have to run as vmail, but I didn’t see any reason why it should run as root and running it as vmail is convenient.

In my setup, Fetchmail gets most of its runtime parameters from a configuration file, /home/vmail/.fetchmailrc. Here is what the file looks like.

# fetchmail configuration file

set postmaster
set syslog

poll pop1.ISP.domain.dom protocol pop3 authenticate password
        user "<username>"
        password "<password>"
        is "andrewISP"

Since this file contains the password to my mail account on my ISP’s server, I’ve set the permissions on this file to 600; something that Fetchmail requires, in fact. It’s nice when a program does the Right Thing by default. Here is a listing of the configuration file.

-rw-------  1 vmail    vmail     230 Mar 26 23:38 /home/vmail/.fetchmailrc

This configuration file tells Fetchmail to connect to my ISP’s mail server using the POP3 protocol, log in with my user ID and password, and deliver any mail it finds there to on my local mail server. The smtpaddress parameter is necessary because otherwise Fetchmail will try to deliver mail to andrewISP@localhost, something my qmail setup doesn’t like. By default, Fetchmail tries to connect to port 25 on localhost to deliver mail it has retrieved which is why I don’t need to tell Fetchmail where my mail server is.

Once Fetchmail was set up, I needed to create an entry in qmail’s user database and set up an account directory in /home/vmail/arda-homeunix-net just like I would with any other mail user account.

And that’s it. For very little effort, I am able to pull all of my mail delivered to my ISP’s mail server into my own mail server where I can manipulate it to my heart’s content.

Starting Processes with Daemontools

Daemontools is a package that includes programs used to control the startup and shutdown of long-running processes. This package is intended to ensure that processes that are supposed to run all the time actually do.

Daemontools on Callisto

I’ve set up netqmail, courierpassd, fam, and SpamAssassin to be controlled by the supervise program from the daemontools package. I also use svscan as the overseer to ensure all processes controlled by supervise are started during system boot. Here’s how I did it.

I have two separate supervise directories, one for netqmail processes and the second for everything else. There really is no good reason that I can see for having netqmail separated like this. My only excuse is that I set up netqmail first and that I was following a recipe. Feel free to put all your run scripts under a single supervise directory.

Here is what my netqmail supervise directory looks like. It is located in /var/qmail/supervise.

drwxr-xr-x  4 root  qmail  512 Dec  3 22:14 supervise
drwxr-xr-x  4 root  qmail  512 Dec  4 00:06 supervise/qmail-send
drwxr-xr-x  3 root  qmail  512 Dec  4 00:06 supervise/qmail-send/log
-rwxr-xr-x  1 root  qmail   30 Dec  3 22:15 supervise/qmail-send/run
-rwxr-xr-x  1 root  qmail   89 Dec  3 22:16 supervise/qmail-send/log/run
drwxr-xr-x  4 root  qmail  512 Dec  4 00:06 supervise/qmail-smtpd
drwxr-xr-x  3 root  qmail  512 Dec  4 00:06 supervise/qmail-smtpd/log
-rwxr-xr-x  1 root  qmail   34 Dec  3 22:23 supervise/qmail-smtpd/run
-rwxr-xr-x  1 root  qmail   95 Dec  3 22:24 supervise/qmail-smtpd/log/run

Once you start supervise the first time, a lot more files and directories will appear under the supervise directory. I’ve listed only the ones that I had to put there myself.

Here are what the four run scripts look like.

File Contents

exec /var/qmail/rc

exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail

exec /var/qmail/smtprc

exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail/smtpd

The qmail-send/run and qmail-smtpd/run scripts simply invoke the run scripts I descibed in the MTA Run Scripts section. The run scripts located in the log directories send all netqmail logs to the directories indicated; in other words, netqmail logs don’t show up in syslog. The setuidgid and multilog programs are also part of the daemontools package by the way.

Before I could start using multilog, I needed to create the directories it would be sending logs to. Here they are.

drwxr-x---  3 qmaill  wheel    512 Dec  9 10:19 /var/log/qmail
drwxr-x---  2 qmaill  wheel    512 Dec 13 15:03 /var/log/qmail/smtpd

The second supervise directory is located in /usr/local and looks like this.

drwxr-xr-x  5 root  wheel  512 Dec 26  2003 supervise
drwxr-xr-x  4 root  wheel  512 Apr 18  2003 supervise/courierpassd
drwxr-xr-x  3 root  wheel  512 Dec  7  2002 supervise/courierpassd/log
-rwxr-x---  1 root  wheel  145 Nov 18  2003 supervise/courierpassd/run
-rwxr-x---  1 root  wheel   64 Dec  8  2002 supervise/courierpassd/log/run
drwxr-xr-x  4 root  wheel  512 Mar  3 18:38 supervise/fam
drwxr-xr-x  3 root  wheel  512 Mar  3 18:38 supervise/fam/log
-rwxr-x---  1 root  wheel  138 Apr 14 12:41 supervise/fam/run
-rwxr-x---  1 root  wheel   56 Mar  3 18:25 supervise/fam/log/run
drwxr-xr-x  4 root  wheel  512 Dec 26  2003 supervise/spamd
drwxr-xr-x  3 root  wheel  512 Dec 26  2003 supervise/spamd/log
-rwxr-x---  1 root  wheel  176 Dec  3 10:54 supervise/spamd/run
-rwxr-x---  1 root  wheel   57 Dec 26  2003 supervise/spamd/log/run

And here are the run scripts.

File Contents

# run tcpserver with just enough privileges to read the authdaemon socket
AUTHUID=`/usr/bin/id -u courier`
AUTHGID=`/usr/bin/id -g courier`

exec /usr/local/bin/tcpserver -v -R -l \
-x /usr/local/etc/tcprules.d/tcp.pop3pw.cdb -u "$AUTHUID" -g "$AUTHGID" \
0 pop3pw /usr/local/sbin/courierpassd -s imap --stderr 2>&1

exec /usr/local/bin/multilog t /var/log/courierpassd

exec /usr/local/bin/fam -f -l -v -c /usr/local/etc/fam.conf 2>&1

exec /usr/local/bin/multilog t /var/log/fam

exec /usr/local/bin/spamd --siteconfigpath=/usr/local/etc/mail/spamassassin \
--pidfile=/var/run/ --syslog=stderr 2>&1

exec /usr/local/bin/multilog t /var/log/spamd

And here are the log directories for courierpassd, fam, and spamd as specified in the log/run scripts.

drwxr-x---  2 root    wheel        512 Aug 21  2003 /var/log/courierpassd
drwxr-x---  2 root    wheel        512 Apr 14 12:40 /var/log/fam
drwxr-x---  2 root    wheel        512 Feb 10 00:02 /var/log/spamd

Courierpassd’s run script is set up much like netqmail’s smtprc script. It uses tcpserver to provide the network connectivity. Three things are of note in this file. One is that I specify the loopback address for courierpassd to listen on. But this doesn’t seem to make any sense because courierpassd must accept connections from Io, my web server, to do any good. I have courierpassd listening on localhost because I use Stunnel to create a secure connection between Callisto and Io. See my Stunnel Setup Doc for more details. The second point is that pop3pw is the alias given to port 106 in my /etc/services file. I’ve also seen poppassd used for this port. Make sure what you put here matches whatever is in your /etc/services file or just put the port number you want here instead. The third point is the –stderr switch used with courierpassd. This switch causes courierpassd logs to go to the directory specified in the log/run file instead of to syslog. This way, logs from tcpserver and courierpassd will go to the same place.

Before setting up Stunnel, I used tcpserver’s -x switch to restrict which IPs could connect to courierpassd. Now I’m using a client certificate with Stunnel which, at least in theory, is a lot more powerful than IP filtering.

You’ll notice that I run tcpserver and thus courierpassd with reduced privileges. Courierpassd doesn’t need to run as root to do it’s job, it just needs to be able to communicate with the domain socket set up by authdaemon from the courier-authlib package. When installed from the FreeBSD port, this socket is located in /var/run/authdaemond which is owned by courier:courier with permissions set to 750. The socket itself has permissions 777 so with courierpassd running as the user courier, it is able to do what it needs to do and I don’t have another process running as root.

Using fam allows me to take advantage of the enhanced idle capability of Courier IMAP. The spamd run scripts are described in my SpamAssassin Setup document.

Once all the supervise directories and run scripts were in place, I needed a way to start everything at system boot. To do this, I use svscan from the daemontools package. I created the directory /var/service and put symlinks into it that point to the various directories under my supervise directories. If that sentence confuses you, don’t worry, it confuses me too. So in the interest of clarity, here is what the /var/service directory looks like.

lrwxr-xr-x  1 root  wheel  34 Mar  3 22:04 courierpassd -> /usr/local/supervise/courierpassd/
lrwxr-xr-x  1 root  wheel  25 Mar  3 18:28 fam -> /usr/local/supervise/fam/
lrwxr-xr-x  1 root  wheel  32 Apr  1 23:59 qmail-send -> /var/qmail/supervise/qmail-send/
lrwxr-xr-x  1 root  wheel  33 Apr  1 23:59 qmail-smtpd -> /var/qmail/supervise/qmail-smtpd/
lrwxr-xr-x  1 root  wheel  27 Mar 28 07:06 spamd -> /usr/local/supervise/spamd/

The last thing to do is activate the startup script in /usr/local/etc/rc.d/ called This file was installed as part of the FreeBSD port of daemontools and all I needed to do to make it work was rename it to The FreeBSD ports system can be really handy at times. Here is what the file looks like.


# $FreeBSD: ports/sysutils/daemontools/files/,v 1.13 2006/02/20 20:47:41 dougb Exp $

# PROVIDE: svscan

# Define these svscan_* variables in one of these files:
#       /etc/rc.conf
#       /etc/rc.conf.local
#       /etc/rc.conf.d/svscan

# It would really, really be a Good Thing(tm) for you to enable some
# of the below control variables and the apropriate ulimit.
# These are only examples.
# Furthermore, you should think about additional limits you might need.
# Or, check login.conf(5) for a suitable alternative.
# If you want to use these examples, please place into /etc/rc.conf.d/svscan.
# I really do suggest you use /var/service as your service spool directory.
# Check hier(7) for reasons.

# 10 Mb
# 20 Mb
# 10 Mb
# 100
# 40

# ulimits
#ulimit -d ${MINSEGMENT}
#ulimit -f ${MAXFILESIZE}
#ulimit -m ${MAXSEGMENT}
#ulimit -n ${MAXFD}
#ulimit -s ${MINSEGMENT}
ulimit -u ${MAXCHILD}

. /etc/rc.subr



load_rc_config $name


svscan_start () {
        echo "Starting svscan."
        /usr/bin/env \
        PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
        /usr/sbin/daemon -f /bin/sh -c "$command $svscan_servicedir 2>&1 | /usr/local/bin/readproctitle service errors: ................................................................................................................................................................................................................................................................................................................................................................................................................ &" > /dev/null

svscan_stop_post () {
        find -L "$svscan_servicedir" -mindepth 1 -maxdepth 2 -type d -name '[^.]*' \( \! -path "$svscan_servicedir/*/*" -or -name 'log' \) -print0 | xargs -0 /usr/local/bin/svc -dx

run_rc_command "$1"

This script directs svscan to start supervise processes for all the run scripts it finds under the /var/service directory. A number of ulimit parameters are provided but I’ve only uncommented the MAXCHILD parameter in order to prevent fork bombs. You may want to explore the other ulimit parameters further to see if any are worth using. Using the script to stop svscan not only stops svscan itself but also every process with a run script under /var/service.

Daemontools on Europa

On Europa, I use daemontools to control netqmail. The set up closely follows that of Callisto although it is simpler since I don’t have an SMTP process running on Europa.

Here is what my qmail supervise directory looks like. It is located in /var/qmail/supervise.

drwxr-xr-x    4 root     qmail        4096 Dec  6 00:19 supervise/qmail-send/
-rwxr-x---    1 root     qmail         218 Aug 26 19:44 supervise/qmail-send/run
drwxr-xr-x    3 root     qmail        4096 Dec  6 00:19 supervise/qmail-send/log/
-rwxr-x---    1 root     qmail          89 Aug 25 11:07 supervise/qmail-send/log/run

Here are what the two run scripts look like.

File Contents

exec /var/qmail/rc

exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail

Here is the log directory used by multilog.

drwxr-x---    3 qmaill   root      4096 Dec  4 02:52 /var/log/qmail/

I have a /service directory on Europa. It contains only one symlink to the qmail-send directory.

lrwxrwxrwx    1 root     root           31 Aug 25 19:14 qmail-send -> /var/qmail/supervise/qmail-send/

Like Callisto, the qmail-send run script points to a script in the /var/qmail directory. The script is listed in the null client Run Scripts section.

The reason I have a /service directory on Europa and not a /var/service directory like on Callisto is because that’s where daemontools put it. On Callisto, I installed daemontools from the FreeBSD ports tree and the port maintainer has evidently set up daemontools to install the service directory under /var. I installed daemontools from a tarball on Europa and so service went into the root directory. I haven’t had any trouble with either setup.

This line in my inittab file ensures that all processes controlled by supervise are started at boot time.



Stopping Spam & Malware

I use a variety of techniques to reduce the amount of unwanted email that reaches the mailboxes on Callisto. Details of the techniques I employ can be found in my SpamAssassin Setup document. Rather than duplicate all that writing, I’ll simply list the various techniques here.

Here are the various techniques I use to stop unwanted mail and the programs or patches involved

Technique Program Host
1. I check incoming connections against DNS Block Lists (DNSBLs). rblsmtpd Thebe
2. I check elements of the SMTP conversation against regex patterns. qregex patch to netqmail Thebe
3. I check RCPT TO against a list of valid recipients. Recipients patch to netqmail Thebe
4. I look for attachments with certain file types. simscan Thebe
5. I scan incoming mail for malware (viruses, trojans, and worms). simscan & Clamav Thebe
6. I scan incoming mail against a spam filter. simscan & SpamAssassin Callisto

The techniques occur in the listed order during mail processing with checks against DNSBL lists happening first and SpamAssassin scanning happening last. The first five techniques are all performed during the SMTP conversation with the remote client and thus allow unwanted email to be rejected instead of bounced. Only SpamAssassin checking occurs later in the delivery cycle. In this case, I don’t bounce mail identified as spam but rather put it in a special folder that exists in each user’s mail account.

There are a few guiding principles I follow when dealing with unwanted mail. These are:

  1. Stop the mail as early in the delivery cycle as possible.
  2. Avoid sending bounce messages whenever possible.
  3. Never drop mail silently. Either reject the mail or deliver it somewhere.

The first point is there to minimize the time and resources my servers have to waste on mail I don’t want. It also makes it easier to fulfill the second point, which is to avoid sending bounce messages. Sending bounces to spam is a useless gesture in the vast majority of cases since the return address is almost always forged. You just end up bothering someone who can’t fix your problem and you compound other peoples’ problems by sending them more unwanted mail. I think the third point is important to deal with false-positives. Everyone is familiar with false-negatives when it comes to unwanted mail; it’s what you get in your inbox despite all the nifty spam-blocking features employed by your mail admin. But false-positives are what cause mail admins to lay awake at night. By never silently dropping mail my servers deem to be spam or otherwise undesirable, I at least have a chance to track down what happened in the event someone doesn’t get that important email that they’ve been breathlessly waiting for.

Mail & DNS

After all of this work, you would think that my mail setup should be complete. Well, not quite. There is one more thing to consider; DNS.

In order for mail to route correctly through my network, I needed to put an MX record into my primary DNS server’s zone files. In fact, for each mail account domain hosted by Callisto (virtual or otherwise), I need a corresponding zone file containing the relevant MX record in my DNS server.

How MX records are set up on Europa and Io, my primary and backup DNS servers, is detailed in my DNS & DHCP Setup document.

Software Home Sites

Clam AntiVirus
Courier Authlib
Courier IMAP server
qmail MTA
SquirrelMail Webmail

Further Reading

In the unlikely event that this document doesn’t answer all your questions, here are some other documents I’ve come across that that may be of help. Remember to check out the home pages listed above as they include plenty of documentation too.

qmail single UID Howto
Home of much qmail documentation, patches, and more
Life with qmail document
Linux Email Server in an NT Domain
qmail Newbie’s Guide to Relaying
Tutorial on how to set up a complete mail server using qmail and Courier-IMAP with lots of bells and whistles