Running qmail on Debian

I used to use qmail for all of my user mail servers since I like the variety of special mail handling that I can configure and I think it does a good job at being a secure mail server. It's always rather interesting to use qmail, though, since it doesn't have a normal license and doesn't follow the standard file system layout conventions. Here are a few notes on how I set it up. (Note that I've since mostly switched to Postfix, and therefore probably won't be updating these notes much.)

Note that Debian does have installer packages for qmail and its prerequisites, and if you want to run qmail but have it look very much like a regular Debian package and log in the regular Debian way, that's one route to go. I tried that for a bit and didn't really like it, but you may have a different experience. (There are apparently also installers that don't try to shuffle things into FHS-compliant locations or use the system log rotation, but I haven't experimented with those.)

These instructions set up the various packages in their default, standard locations, which aren't even remotely FHS-compliant.


You don't actually need any other packages than just qmail to run it, but it's much, much nicer to also use daemontools to start and stop it and manage logs (instead of an init script and splogger to log to syslog), and tcpserver just works far better than inetd or even xinetd for most purposes in my opinion. So I'd start by installing those packages.

You can get the current versions from:

For each package, I just followed the standard installation instructions from the web pages, with one exception. This software has a problem with how it handles errno that will cause it to eventually break with newer versions of Linux, but thankfully it's easy to fix. In all of the *.c and *.h files in the ucspi-tcp directory created by untarring the tar file, and in all the *.c and *.h files in /package/admin/daemontools/src after untarring the distribution, replace any instance of extern int errno; with #include <errno.h>. This is generally as easy as running:

  perl -i -pe 's/^extern int errno;/\#include <errno.h>/' *.c *.h

in each of those directories. Then proceed with the regular build and installation instructions.

Note that after installing daemontools, you may want to reboot to make sure that everything is consistent, although you may not have to. It adds an invocation of svscanboot to /etc/inittab that may not take effect until you reboot or run telinit q.

About daemontools

Now that you have daemontools installed, you can use it only for qmail, but it's also generally a pretty useful way of installing services. You can find out more about it from the above-mentioned web site, but basically it's a system for starting and monitoring services to keep them running.

At boot time, the directory /service is scanned for subdirectories. In each subdirectory that contains an executable file named run, that file is executed. If that process ever exits, it's restarted. There are a few other bits related to services that log messages to stdout, where you can set up a log subdirectory of the service directory with its own run script to handle those log messages, but that's basically it.

Obviously, this can't be used for services that background themselves after starting, since the monitor and restart system doesn't work right. But for things like tcpserver (basically a single-port inetd with some nice features), dnscache, or even just random things that you wrote yourself and want to run as a daemon, this is great.

I recommend reading the daemontools web pages for more information about how to set this up. It's really cool.

Install qmail

Get qmail from and build and install it following the instructions. As with daemontools and tcpserver, you'll need to change the references to errno after unpacking the source tarball. See above for how to do that.

You will also need to add the qmail users and groups as described in the qmail documentation (in the file INSTALL.ids). None of the commands listed quite work for Debian; instead, use:

  addgroup nofiles
  adduser --system --home /var/qmail --shell /dev/null --ingroup nofiles alias
  adduser --system --home /var/qmail --shell /dev/null --ingroup nofiles qmaild
  adduser --system --home /var/qmail --shell /dev/null --ingroup nofiles qmaill
  adduser --system --home /var/qmail --shell /dev/null --ingroup nofiles qmailp
  addgroup qmail
  adduser --system --home /var/qmail --shell /dev/null --ingroup qmail qmailq
  adduser --system --home /var/qmail --shell /dev/null --ingroup qmail qmailr
  adduser --system --home /var/qmail --shell /dev/null --ingroup qmail qmails

The installation will put your qmail installation into /var/qmail; you may want to add /var/qmail/bin to your root user's default PATH setting so that you can easily run qmail-qread and similar commands.

Set up qmail to run

First, create the structure under /service so that svscan will start qmail, qmail's logging daemon, the SMTP listener, and the logging daemon for it. Do the following as root:

  mkdir /service/qmail
  mkdir /service/qmail/supervise
  mkdir /service/qmail/log
  mkdir /service/qmail/log/supervise
  mkdir /service/qmail-smtpd
  mkdir /service/qmail-smtpd/supervise
  mkdir /service/qmail-smtpd/log
  mkdir /service/qmail-smtpd/log/supervise
  chmod 1755 /service/qmail
  chmod 1755 /service/qmail-smtpd
  chmod 750 /service/qmail/supervise
  chmod 750 /service/qmail/log/supervise
  chmod 750 /service/qmail-smtpd/supervise
  chmod 750 /service/qmail-smtpd/log/supervise

This sets things up so that users in root's group (generally 0) can use the supporting programs like svstat to see what's up with these services (because the supervise directories are mode 750).

Now, you need to create run scripts in /service/qmail, /service/qmail/log, /service/qmail-smtpd, and /service/qmail-smtpd/log. For an example of a run script for /service/qmail, you can take a look at /var/qmail/boot, but you don't want the splogger portions of those commands. Here's what I use:

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

This delivers all mail to a file named Mailbox in the user's home directory by default. Another option that's somewhat more "Debian-like" is to install the procmail package and then use:

  exec env - PATH="/var/qmail/bin:$PATH" qmail-start '|preline procmail'

This will use procmail as the delivery agent and put new mail in /var/mail instead of in the user's home directory. I prefer to deliver mail into the user's home directory so that it's easier to manage user quotas, but your opinions may vary.

The /service/qmail-smtpd/run file should look like:

  exec /command/softlimit -m 2000000 \
      /usr/local/bin/tcpserver -v -R -u 106 -g 103 0 smtp \
      /var/qmail/bin/qmail-smtpd 2>&1

but with 106 replaced with whatever UID the qmailr user ended up with on your system and with 103 replaced by whatever GID the qmail group ended up with on your system.

Finally, both /service/qmail/log/run and /service/qmail-smtpd/log/run should look something like:

  exec /command/setuidgid qmaill /command/multilog t s1048576 /var/log/qmail

The last argument to multilog is the directory into which to log, and it can't be the same for both qmail and qmail-smtpd (of course). I use /var/log/qmail for qmail and /var/log/smtpd for qmail-smtpd. See for more information on multilog and how it works.

You may also want to monitor the qmail logs for any problems. I use my own multilog-watch program to do that.

Configuring qmail

If you've finished the above steps, your qmail system should now be up and running. Now, you need to configure it. All of qmail's configuration files live in /var/qmail/control. I'm not going to cover the configuration in detail, since there are other, better guides for that. I recommend reading the qmail web pages and the man pages in /var/qmail/man in detail; in particular, run:

  man -M /var/qmail/man qmail-control
  man -M /var/qmail/man qmail-send
  man -M /var/qmail/man qmail-smtpd

in addition to reading the web pages. There are a lot of possibilities here depending on what you want to do.

Replacing the system mailer

Actually replacing the system mail daemon requires a bit of fiddling, since you have to tell the Debian packaging system that you still have a mail transport agent or it will try to remove all sorts of useful programs, like all of your mail clients. The way to do this is with the package equivs. Install equivs with apt-get, and then read /usr/share/doc/equivs/README.Debian. The package comes with /usr/share/doc/equivs/mail-transport-agent.ctl, which is a great control file to use to create a dummy package for this purpose; I use it without any changes.

Follow the equivs instructions and then install the resulting .deb file with dpkg -i. This will also remove your existing Debian-installed mail system.

Now, you can make qmail the default for those programs on your system that send mail by typing:

  ln -s -f /var/qmail/bin/sendmail /usr/sbin/sendmail

as root. (You may also want to create a /usr/lib/sendmail link to /var/qmail/bin/sendmail if you use old software that has that sendmail path hard-coded.)

Accepting local relaying

One change that you may need to do depending on what software you're running is to allow relaying from the local system. By default, as long as you've not done something stupid like deleting /var/qmail/control/rctphosts, qmail only accepts mail for domains that you've listed and rejects all general relaying attempts. Some software, however, like Mailman, really wants to be able to connect to the local SMTP port and send mail out that way.

To support this, create a /var/qmail/tcpserver directory and in it put a file named tcprules with the following contents:,RELAYCLIENT=""

replacing with your local IP address. This sets the RELAYCLIENT environment variable only for connections from the local system or to the loopback interface, which tells qmail-smtpd to allow general relaying only from those connections.

Now, run:

  cd /var/qmail/tcpserver
  /usr/local/bin/tcprules tcprules.cdb tcprules.tmp < tcprules

to generate a static database from your rules file and modify /service/qmail-smtpd/run to look more like:

  exec /command/softlimit -m 2000000 \
      /usr/local/bin/tcpserver -v -R -u 106 -g 103 \
          -x /var/qmail/tcpserver/tcprules.cdb \
          0 smtp /var/qmail/bin/qmail-smtpd 2>&1

(again replacing 106 and 103 as appropriate). Basically, add the -x option to the tcpserver invocation to tell it to use that rules database for incoming connections.

Mail in user home directories

If you follow my configuration, you're now delivering mail into ~/Mailbox for each user rather than into /var/mail. This requires changing a few other things as well.

First, you need to make sure that the MAIL environment variable for all of your users is set to $HOME/Mailbox rather than its default value in /var/mail. To do this, modify /etc/login.defs and uncomment the MAIL_FILE line, changing its value to Mailbox. You'll also need to comment out the MAIL_DIR line.

Some logins don't go through login (particularly logins via ssh or Kerberos). For those, you'll need to modify the shell startup files in /etc/profile, /etc/csh.cshrc, and /etc/zsh/zshenv (or /etc/zshenv in older versions of Debian). In /etc/profile, add something like:

  export MAIL

In /etc/zsh/zshenv, add:

  export MAIL=$HOME/Mailbox

And in /etc/csh.cshrc, add:

  setenv MAIL $HOME/Mailbox

Users will also have to be careful about their procmail rules, since procmail's notion of the user's mail spool isn't configurable on a system-wide basis. Basically, all procmail users need to set ORGMAIL and DEFAULT to $HOME/Mailbox. Because of this, if you use procmail a lot, it's probably better to just use procmail as your delivery agent (as described above) and thereby use /var/mail as the spool directory.

Finally, if you run qpopper as your POP daemon, you can configure it to look in the right location by editing /etc/qpopper.conf and adding:

  set home-dir-mail = "Mailbox"

Note that there may be many other programs that expect user mail in /var/mail. They're all supposed to pay attention to the MAIL environment variable in preference to their default, but there are always some that don't do this.

Last spun 2013-07-01 from thread modified 2013-01-04