If you're diving into this section, chances are you're either entirely new to qmail, or you're looking to get a feel of this book. There are many very good qmail installation guides and tutorials that are available for free on the Internet. The current version of qmail was published on June 15th, 1998. Since then what has changed the most about the qmail experience is the accumulation of expertise and experience in using and tailoring it for the most common situations and even some uncommon ones.
Without delving into the architecture, qmail is extremely modular. In many ways, qmail is less of a mail server and more of mail server architecture. Pieces of qmail can be replaced, rearranged, filtered, and extended as necessary to achieve virtually any feature the administrator desires. However, along the same lines, qmail requires certain assistance to provide some features one ordinarily expects. Qmail's SMTP server, for example, cannot talk to the network by itself; this ability is provided by software like inetd
or tcpserver
or similar. This design makes qmail's components secure and much simpler and easier to verify. This design also makes the details of how the qmail components are hooked together a vital part of the system configuration, as opposed to a single monolithic server with a complex configuration file that can achieve the same thing.
To get the most out of this book, you're going to need a basic understanding of UNIX-style operating system conventions and features, simple command-line operations, and how to edit text files.
Qmail comes with a set of minimal install instructions, in a file named INSTALL
. It contains eighteen relatively basic steps for compiling qmail on most systems and for getting it running. These are somewhat simple, but can be trimmed even further if you're not trying to replace an existing mail server.
Compiling qmail is generally very easy. Before compiling qmail, first obtain the prerequisites:
A Unix-style operating system (such as Linux, BSD, Solaris, etc.)
A working C compiler (preferably executable using
cc
, as that requires less configuration before compiling) and the standard C development systemA case-sensitive filesystem
Having a case-sensitive filesystem is important because during installation, qmail uses several files that are different only in the capitalization of their name. For example, INSTALL
is a text file describing basic installation procedures, while install
is a script for putting files in the correct places with the correct permissions. The qmail distribution can be modified to work around that problem, but that is a little outside the purview of this book.
With those prerequisites, installing a bare-bones version of qmail is a straightforward five-step process as follows:
1. Prepare the system: add one directory (
/var/qmail
), seven users (qmaild, qmaill, qmailp, qmailq, qmailr, qmails, and alias), and two groups (qmail and nofiles).2. Run
make setup install
to compile and install all the necessary binaries.3. Run the
config
(orconfig-fast)
script to create the basic configuration files.4. Create the necessary, minimum account aliases.
5. Tell qmail where to deliver mail by default.
Simple, isn't it? Let's go into a bit more detail here.
On most UNIX systems it should be relatively easy to add users and groups, using tools like useradd, adduser, mkuser
, or something similar. For example, on many Linux distributions, the commands for preparing the system are as follows:
mkdir /var/qmail
groupadd nofiles
useradd -d /var/qmail/alias -s /bin/false -g nofiles alias
useradd -d /var/qmail -s /bin/false -g nofiles qmaild
useradd -d /var/qmail -s /bin/false -g nofiles qmaill
useradd -d /var/qmail -s /bin/false -g nofiles qmailp
groupadd qmail
useradd -d /var/qmail -s /bin/false -g qmail qmailq
useradd -d /var/qmail -s /bin/false -g qmail qmailr
useradd -d /var/qmail -s /bin/false -g qmail qmails
The users are required as part of qmail's security setup; almost every major portion of qmail runs as a different user. The reason for this is simple—it allows qmail to use standard UNIX user protections to enforce separation between its components, which communicate via tightly-controlled interfaces (namely, pipes and environment variables). This user separation is the backbone of qmail's security model—a model that has done exceedingly well and has been adopted by other security-conscious programs (e.g. OpenSSH). To complete the protection that these users provide, it's a good idea to ensure that each of these users cannot be used by anyone to log into the system. On most modern systems, this is achieved by not giving the user a working shell (e.g. /bin/false)
.
The second step is the compilation step. Generally, this is the simplest of the steps, provided that the necessary tools (a compiler and the make
utility) are available. Qmail will compile on most systems without further configuration, by simply executing the command make setup check
. The exceptions are modern Linux systems that use a more recent version of glibc than version 2.3.1. On these systems, it is necessary to edit the conf-cc
file that comes with qmail before compiling, so that it looks like the following:
gcc -include /usr/include/errno.h
If your compiler cannot be run using the cc
command, edit the conf-cc
file to contain the correct command to compile files.
The third step simply adds the most minimal configuration information that qmail requires for functioning—the Fully Qualified Domain Name (FQDN) of the host computer. The term "fully-qualified" means that the FQDN not only contains the host name, but also the full domain name. For example, to set up a computer named mail
as part of example.com's
computer network, the FQDN would be mail.example.com
. To configure qmail for this computer, the minimal configuration command would then be:
./config-fast mail.example.com
The alternative command, ./config
, does the same thing that ./config-fast
does, however, it obtains the FQDN by looking up the computer's IP address in DNS. If the system is already set to go with the IP address it will always have, this is a convenient way to avoid extra typing. However, if the system's network configuration is not in its final state, using ./config
will probably produce an incorrect set of configuration files. Running either command overwrites any existing configuration files.
The fourth step adds the accounts that are required by the various email standards documents (in particular, RFC 822). The following accounts are required:
postmaster@yourdomain.com mailer-daemon@yourdomain.com abuse@yourdomain.com root@yourdomain.com
The last one, root@yourdomain.com
, needn't necessarily exist. However, qmail does not deliver mail to the real root user, and the address is commonly assumed to refer to the administrator of the machine (for example, by scripts and monitoring programs) when the administrator needs to be notified of something. Thus, creating an alias for root is generally a good idea.
Aliases are defined by creating files in the home directory of the alias user. If the alias user has been created according to the above instructions, that directory is /var/qmail/alias
. The general way of referring to this directory is ~alias/
. The alias-defining files in this directory must have very specific names, all beginning with .qmail
and ending with the name of the alias. For example, the postmaster alias is established by creating a file named .qmail-postmaster
in the directory ~alias/
. The mailer-daemon alias is established by creating a file named .qmail-mailer-daemon
, and so forth. Capitalization for account names is always converted to lowercase for delivery, so don't use capital letters in .qmail
filenames.
The content of these files specifies exactly what should happen to email that is sent to one of these aliases. In general, the syntax is identical to the generic dot-qmail (.qmail
) file syntax, which is discussed later in this book, but the exception is the bare minimum: an empty file. If an alias is established with an empty file, it will be delivered as specified by the default delivery mechanism (for more details refer to the Default Mail Delivery section).
The simplest option is to put an account name in those files, which tells qmail to forward all mail sent to these aliases to the account specified. For example, if all email addressed to root@yourdomain.com
should be delivered to an account named steve, put steve
into the ~alias/.qmail-root
file.
It is important to note that these files should have very specific permissions—they should be readable by any user, but only writable by the root user. This may not be the default when these files are created. To set the permissions to what they need to be, run a command that looks something like the following:
chown root ~alias/.qmail-root chmod 644 ~alias/.qmail-root
The fifth and final step is to tell qmail how to deliver mail by default. Default means how qmail delivers all mail unless told to do something else by a .qmail
file. Generally, this is done by selecting a startup script from the /var/qmail/boot
directory and copying it to the file /var/qmail/rc
.
In the /var/qmail/boot
directory, there are several files, each of which can start up qmail with a different default delivery method. The ones that come with qmail are:
home:
Delivers email to the fileMailbox
in the user's home directory.home+df:
Supports Sendmail-style.forward
files, and otherwise is the same ashome
.proc:
Hands the email toprocmail
for delivery.proc+df:
Supports Sendmail-style.forward
files, and otherwise is the same asproc
.binm1:
Hands the email to BSD 4.4's binmail program (mail.local) for delivery.binm1+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm1
.binm2:
Hands the email to SVR4's binmail program (/bin/mail-r)
for delivery.binm2+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm2
.binm3:
Hands the email to the V7 binmail program (/bin/mail-f)
for delivery.binm3+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm3
.
Unless you are migrating from an older mail server and have a reason to want the compatibility features, the file to use is either home
or proc
. The simplest is home
.
Once all five steps are completed, a working, bare-bones installation of qmail is ready in /var/qmail
. However, in many situations, a barebones installation is insufficient.
The basic questions to answer when configuring an email server on a new system include:
What should be done with mail when it is received?
Which mail should be accepted?
The most common and simplest answers to the first question generally fall into one of the following two categories: either mail should be relayed to a smarter mail server or the mail should be delivered locally.
The second question can often become far more complicated due to spam and viruses and the like, but the most basic answer is generally a list of domain names for which this email server is responsible.
As you can tell already, various answers to these questions can result in wildly different behaviors. For example, if no mail should be accepted from the network, no mail should be delivered locally, and all mail should be forwarded to a specific mail server, then this is considered mini-qmail. In such a situation, many of the more complex features of qmail can be eliminated. In different circumstances, the qmail server may need to accept any and all email and forward it to a central mail server (for example, a mail proxy or a caching forwarder). Or it may need to accept email for a specific domain and deliver it to system-defined users (the standard setup). Or it may need to accept email for a set of domains and deliver it locally via some virtual-domain configuration. There could be any number of additional complications, twists, and turns.
The most basic answers to these questions are specified to qmail via configuration files. Which mail should be accepted is generally specified by files in the /var/qmail/control
directory, and what to do with mail that has been accepted is generally specified in a combination of files in the control
directory and the rc
file (which was set up in Default Mail Delivery section of the installation procedure). Note though, that the rc
file is a shell script. Much of qmail configuration is in the form of scripts controlling how qmail and its related binaries are run.
The most basic, most important control files for qmail are: me, rcpthosts, locals, smtproutes
, and defaultdomain
. The files are not necessarily created by default or by the ./config
scripts; but they control qmail's most important functionality. They control, respectively, the name of the server, which domains' mail to accept, which domains are to be considered local once mail addressed to them is accepted for delivery, where to send outbound mail, and which domain to append to bare
usernames to transform them into real email addresses. The defaultdomain
and me
files are simple one-line files. In the case of me
, this line is considered the name of the server. In the case of defaultdomain
, this line is considered the name to append (for example, example.com)
to a bare username (for example, user) to construct a valid email address (for example, user@example.com)
when necessary. The rcpthosts
and locals
files are simply lists of domains, one domain per line in the file. The most complex of the four, smtproutes
, is also rather simple. Each line of the file consists of three fields separated by colons. The first field is the domain that needs to be routed this way and the second field is the domain name or IP address (in square brackets) of the server to which matching email must be sent. The third field is the port on the server to connect to, which if not present, defaults to port 25. For example:
somewhere.com:[1.2.3.4]
This line in the file informs qmail that any email sent to an address ending in @somewhere.com
must be forwarded to the IP address 1.2.3.4
. The files smtproutes, rcpthosts
, and locals
can all use prefix-wildcards. A prefix-wildcard is a line that begins with a period, followed by the suffix that must match following the period. For example:
.somewhere.com:mail.isp.com
This line in the smtproutes
file will match email addresses ending in @here.somewhere.com, @there.somewhere.com, @anywhere.somewhere.com
, and so forth, where there is an arbitrary string and a period preceding somewhere.com
. Note that it doesn't match the bare @somewhere.com
. Emails addressed to matching domains are forwarded to mail.isp.com
.
Finally there is the special case, where there is nothing to the left of the first colon as shown in the following example:
:mail.isp.com:1000
This line in the smtproutes
file will send all email to the mail.isp.com
server listening on port 1000
. In the smtproutes
file, the first match is the one that is used, and this line will match anything. As such, it's usually at the end of the file.
There are many more files that qmail looks for in the /var/qmail/control
directory. Explanations of how they work and what they do can be found in the qmail man pages, however, they are generally for more involved configuration tasks and non-basic qmail installations.
Default delivery instructions are part of simple execution.
There are two primary architectural segments of qmail involved in setting up a standard SMTP email server. The first is the set of programs that work together to perform mail deliveries, either locally or remotely, and the second is the set of programs that work together to accept messages via the SMTP protocol.
The programs that work together to perform mail deliveries are: qmail-send, qmail-lspawn, qmail-rspawn
, and qmail-clean
, as well as any program that they spawn to complete their tasks (like qmail-remote, qmail-local, procmail
, etc.). Most of these have corresponding users. In particular, qmail-send
and qmail-clean
operate as the qmails user, and qmail-rspawn
(and qmail-remote)
operate as qmailr. The qmail-lspawn
program runs as root, because it must be able to deliver mail to each user as that user. In any case, all of these programs are spawned by the command qmail-start
. This command takes two optional arguments—a default delivery command and a logging command. To understand exactly how this works, take a look at the most basic of the scripts in the /var/qmail/boot
directory, home:
#!/bin/sh # Using splogger to send the log through syslog. # Using qmail-local to deliver messages to ~/Mailbox by default. exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Mailbox splogger qmail
The first part of this script is fairly straightforward: using the env
command to remove all environment variables before executing qmail-start
, it then sets the PATH
environment variable to make sure that the qmail bin
directory is the first place searched for qmail's binaries. The second part, executing qmail-start
with arguments, requires a little more explanation.
When qmail makes an email delivery, every delivery is made from the perspective of a program running as the receiving user, in the receiving user's home directory. Delivery instructions are treated as if they came from a dot-qmail file, with one delivery instruction per line. From that point onwards, file names are treated as mbox-formated mailboxes, directory names (indicated by ending a file name with a forward-slash (/)) are treated as Maildir-formatted mailboxes, and commands (indicated by starting the line with a pipe symbol (|)) are all located and executed from within the addressed user's home directory. Thus, using a relative file name, such as ./Mailbox
, specifies a file named Mailbox
within the current directory at the time of delivery i.e. the addressed user's home directory.
In this case, the default delivery method is very simple, deliver mail to an mbox-formatted file named Mailbox
in the user's home directory. However, the argument specifying the default delivery method can be more complex. Take, for example, the home+df
file in /var/qmail/boot:
#!/bin/sh # Using splogger to send the log through syslog. # Using dot-forward to support sendmail-style ~/.forward files. # Using qmail-local to deliver messages to ~/Mailbox by default. exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start '|dot-forward .forward ./Mailbox' splogger qmail
Note that because of the rules of shell-script quoting, the first argument to qmail-start
in this case is the full text between the single quotes, or:
|dot-forward .forward ./Mailbox
Note that the single argument is, in fact, two lines. Just as if these lines were in the user's .qmail
file, this causes the dot-forward
command to run first, and if it returns with a code that indicates that the mail has been delivered via instructions in a .forward
file, the delivery is considered complete. On the other hand, if it returns with a code that indicates that the user did not have a .forward
file in his or her home directory, qmail will instead deliver mail to the Mailbox
file, just as it would have if the home
file's delivery instructions were used.
The text after the mail-delivery specification causes qmail-send
to send all logging information to the program specified. In this case, the splogger
program will be run with the argument qmail
. The splogger
program takes the output from qmail-send
, prefixes it with "qmail", and logs it via the standard syslog mechanism. If neither the splogger
command nor any other command is provided as an argument to qmail-send, qmail-send
will send its logging information to standard output (or rather, file descriptor one).
To run this program by hand, simply run your chosen rc
file, as follows:
/bin/sh /var/qmail/rc &
The ampersand at the end ensures that the program executes in the background.
The set of programs that provide SMTP service—receiving SMTP connections (and thus, email) from the network—is organized around qmail-smtpd
. Rather than including basic networking features in the qmail SMTP daemon executable, qmail-smtpd
, qmail pushes that responsibility to a helper program such as tcpserver, inetd, xinetd
, or tcpsvd
, among others. This design decision makes for many useful opportunities. For example, the qmail SMTP service can be tested from the command-line without needing extra software by simply running /var/qmail/bin/qmail-smtpd
. (Note that the DATA phase of the SMTP conversation requires CRLFs rather than simply LFs. The correct line endings can be generated by pressing Ctrl V and then pressing Enter twice.)
Getting qmail-smtpd
to listen to the network requires extra software. Many systems come with either inetd
or xinetd
and they can be configured to run qmail-smtpd
very easily. For example, an inetd.conf
entry for qmail-smtpd
might look like this (all one line):
smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env tcp-env /var/qmail/bin/qmail-smtpd
The current best practice for running qmail-smtpd
is to use the tcpserver
program, also written by the author of qmail, Dr. Bernstein, which is distributed as part of the ucspi-tcp package (http://cr.yp.to/ucspi-tcp.html). It can be used as follows:
tcpserver -u `id -u qmaild` -g `id -g qmaild` \
0 smtp /var/qmail/bin/qmail-smtpd &
This command can be run manually, added to your system's startup commands, or executed using Bernstein's daemontools (http://cr.yp.to/daemontools.html) package. If added to your system's startup commands, the ampersand (&) is critical. The arguments to tcpserver
are straightforward—first, the user and group IDs, then 0
to specify that it will listen to all network interfaces, then smtp
to specify that it will use the SMTP port (25), and finally, the command to be run when a connection is made to that network port.
Standard qmail-smtpd
does not take any run-time arguments; however, its behavior can be modified at run time by using environment variables. In particular, qmail-smtpd
pays attention to the following environment variables:
Environment Variable |
Description |
---|---|
|
The DNS hostname corresponding to the local interface in the connection. |
|
The local IP address in the connection. |
|
The local port number (usually 25 when used with |
|
The DNS hostname of the remote system. |
|
The username responsible for the connection (usually determined using the ident protocol). |
|
The IP address of the remote system. |
|
The port number used by the remote system. |
|
The maximum number of bytes allowed in a message. |
|
The existence of this variable (even if it contains an empty string) allows the sender to relay any email message. The content of this variable is appended to each recipient address. |
Most of these variables (the ones that begin with TCP) are set by the program that handles the network operations. The tcpserver
and tcpsvd
programs set these variables. For programs that do not set these variables (for example, inetd
and xinetd), tcp-env
will set them. The environment variable you will most commonly need to set yourself is RELAYCLIENT
. If this variable is present in the environment, qmail-smtpd
accepts any mail for delivery even if the destination addresses are not in the control/rcpthosts
file. For example, an ISP that relays email from all of its customers generally adds the RELAYCLIENT
variable to qmail-smtpd's
environment, if the connecting client is in its network.
While tcpserver, tcpsvd
, and tcp-env
will set specific environment variables, any other variable (such as RELAYCLIENT)
will generally need to be set using a more generic method. Environment variables can be set in many ways, like using the standard env
utility, the shell's export/setenv
features, and tcprules
files.
Qmail comes with a set of minimal install instructions, in a file named INSTALL
. It contains eighteen relatively basic steps for compiling qmail on most systems and for getting it running. These are somewhat simple, but can be trimmed even further if you're not trying to replace an existing mail server.
Compiling qmail is generally very easy. Before compiling qmail, first obtain the prerequisites:
A Unix-style operating system (such as Linux, BSD, Solaris, etc.)
A working C compiler (preferably executable using
cc
, as that requires less configuration before compiling) and the standard C development systemA case-sensitive filesystem
Having a case-sensitive filesystem is important because during installation, qmail uses several files that are different only in the capitalization of their name. For example, INSTALL
is a text file describing basic installation procedures, while install
is a script for putting files in the correct places with the correct permissions. The qmail distribution can be modified to work around that problem, but that is a little outside the purview of this book.
With those prerequisites, installing a bare-bones version of qmail is a straightforward five-step process as follows:
1. Prepare the system: add one directory (
/var/qmail
), seven users (qmaild, qmaill, qmailp, qmailq, qmailr, qmails, and alias), and two groups (qmail and nofiles).2. Run
make setup install
to compile and install all the necessary binaries.3. Run the
config
(orconfig-fast)
script to create the basic configuration files.4. Create the necessary, minimum account aliases.
5. Tell qmail where to deliver mail by default.
Simple, isn't it? Let's go into a bit more detail here.
On most UNIX systems it should be relatively easy to add users and groups, using tools like useradd, adduser, mkuser
, or something similar. For example, on many Linux distributions, the commands for preparing the system are as follows:
mkdir /var/qmail
groupadd nofiles
useradd -d /var/qmail/alias -s /bin/false -g nofiles alias
useradd -d /var/qmail -s /bin/false -g nofiles qmaild
useradd -d /var/qmail -s /bin/false -g nofiles qmaill
useradd -d /var/qmail -s /bin/false -g nofiles qmailp
groupadd qmail
useradd -d /var/qmail -s /bin/false -g qmail qmailq
useradd -d /var/qmail -s /bin/false -g qmail qmailr
useradd -d /var/qmail -s /bin/false -g qmail qmails
The users are required as part of qmail's security setup; almost every major portion of qmail runs as a different user. The reason for this is simple—it allows qmail to use standard UNIX user protections to enforce separation between its components, which communicate via tightly-controlled interfaces (namely, pipes and environment variables). This user separation is the backbone of qmail's security model—a model that has done exceedingly well and has been adopted by other security-conscious programs (e.g. OpenSSH). To complete the protection that these users provide, it's a good idea to ensure that each of these users cannot be used by anyone to log into the system. On most modern systems, this is achieved by not giving the user a working shell (e.g. /bin/false)
.
The second step is the compilation step. Generally, this is the simplest of the steps, provided that the necessary tools (a compiler and the make
utility) are available. Qmail will compile on most systems without further configuration, by simply executing the command make setup check
. The exceptions are modern Linux systems that use a more recent version of glibc than version 2.3.1. On these systems, it is necessary to edit the conf-cc
file that comes with qmail before compiling, so that it looks like the following:
gcc -include /usr/include/errno.h
If your compiler cannot be run using the cc
command, edit the conf-cc
file to contain the correct command to compile files.
The third step simply adds the most minimal configuration information that qmail requires for functioning—the Fully Qualified Domain Name (FQDN) of the host computer. The term "fully-qualified" means that the FQDN not only contains the host name, but also the full domain name. For example, to set up a computer named mail
as part of example.com's
computer network, the FQDN would be mail.example.com
. To configure qmail for this computer, the minimal configuration command would then be:
./config-fast mail.example.com
The alternative command, ./config
, does the same thing that ./config-fast
does, however, it obtains the FQDN by looking up the computer's IP address in DNS. If the system is already set to go with the IP address it will always have, this is a convenient way to avoid extra typing. However, if the system's network configuration is not in its final state, using ./config
will probably produce an incorrect set of configuration files. Running either command overwrites any existing configuration files.
The fourth step adds the accounts that are required by the various email standards documents (in particular, RFC 822). The following accounts are required:
postmaster@yourdomain.com mailer-daemon@yourdomain.com abuse@yourdomain.com root@yourdomain.com
The last one, root@yourdomain.com
, needn't necessarily exist. However, qmail does not deliver mail to the real root user, and the address is commonly assumed to refer to the administrator of the machine (for example, by scripts and monitoring programs) when the administrator needs to be notified of something. Thus, creating an alias for root is generally a good idea.
Aliases are defined by creating files in the home directory of the alias user. If the alias user has been created according to the above instructions, that directory is /var/qmail/alias
. The general way of referring to this directory is ~alias/
. The alias-defining files in this directory must have very specific names, all beginning with .qmail
and ending with the name of the alias. For example, the postmaster alias is established by creating a file named .qmail-postmaster
in the directory ~alias/
. The mailer-daemon alias is established by creating a file named .qmail-mailer-daemon
, and so forth. Capitalization for account names is always converted to lowercase for delivery, so don't use capital letters in .qmail
filenames.
The content of these files specifies exactly what should happen to email that is sent to one of these aliases. In general, the syntax is identical to the generic dot-qmail (.qmail
) file syntax, which is discussed later in this book, but the exception is the bare minimum: an empty file. If an alias is established with an empty file, it will be delivered as specified by the default delivery mechanism (for more details refer to the Default Mail Delivery section).
The simplest option is to put an account name in those files, which tells qmail to forward all mail sent to these aliases to the account specified. For example, if all email addressed to root@yourdomain.com
should be delivered to an account named steve, put steve
into the ~alias/.qmail-root
file.
It is important to note that these files should have very specific permissions—they should be readable by any user, but only writable by the root user. This may not be the default when these files are created. To set the permissions to what they need to be, run a command that looks something like the following:
chown root ~alias/.qmail-root chmod 644 ~alias/.qmail-root
The fifth and final step is to tell qmail how to deliver mail by default. Default means how qmail delivers all mail unless told to do something else by a .qmail
file. Generally, this is done by selecting a startup script from the /var/qmail/boot
directory and copying it to the file /var/qmail/rc
.
In the /var/qmail/boot
directory, there are several files, each of which can start up qmail with a different default delivery method. The ones that come with qmail are:
home:
Delivers email to the fileMailbox
in the user's home directory.home+df:
Supports Sendmail-style.forward
files, and otherwise is the same ashome
.proc:
Hands the email toprocmail
for delivery.proc+df:
Supports Sendmail-style.forward
files, and otherwise is the same asproc
.binm1:
Hands the email to BSD 4.4's binmail program (mail.local) for delivery.binm1+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm1
.binm2:
Hands the email to SVR4's binmail program (/bin/mail-r)
for delivery.binm2+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm2
.binm3:
Hands the email to the V7 binmail program (/bin/mail-f)
for delivery.binm3+df:
Supports Sendmail-style.forward
files, and otherwise is the same asbinm3
.
Unless you are migrating from an older mail server and have a reason to want the compatibility features, the file to use is either home
or proc
. The simplest is home
.
Once all five steps are completed, a working, bare-bones installation of qmail is ready in /var/qmail
. However, in many situations, a barebones installation is insufficient.
The basic questions to answer when configuring an email server on a new system include:
What should be done with mail when it is received?
Which mail should be accepted?
The most common and simplest answers to the first question generally fall into one of the following two categories: either mail should be relayed to a smarter mail server or the mail should be delivered locally.
The second question can often become far more complicated due to spam and viruses and the like, but the most basic answer is generally a list of domain names for which this email server is responsible.
As you can tell already, various answers to these questions can result in wildly different behaviors. For example, if no mail should be accepted from the network, no mail should be delivered locally, and all mail should be forwarded to a specific mail server, then this is considered mini-qmail. In such a situation, many of the more complex features of qmail can be eliminated. In different circumstances, the qmail server may need to accept any and all email and forward it to a central mail server (for example, a mail proxy or a caching forwarder). Or it may need to accept email for a specific domain and deliver it to system-defined users (the standard setup). Or it may need to accept email for a set of domains and deliver it locally via some virtual-domain configuration. There could be any number of additional complications, twists, and turns.
The most basic answers to these questions are specified to qmail via configuration files. Which mail should be accepted is generally specified by files in the /var/qmail/control
directory, and what to do with mail that has been accepted is generally specified in a combination of files in the control
directory and the rc
file (which was set up in Default Mail Delivery section of the installation procedure). Note though, that the rc
file is a shell script. Much of qmail configuration is in the form of scripts controlling how qmail and its related binaries are run.
The most basic, most important control files for qmail are: me, rcpthosts, locals, smtproutes
, and defaultdomain
. The files are not necessarily created by default or by the ./config
scripts; but they control qmail's most important functionality. They control, respectively, the name of the server, which domains' mail to accept, which domains are to be considered local once mail addressed to them is accepted for delivery, where to send outbound mail, and which domain to append to bare
usernames to transform them into real email addresses. The defaultdomain
and me
files are simple one-line files. In the case of me
, this line is considered the name of the server. In the case of defaultdomain
, this line is considered the name to append (for example, example.com)
to a bare username (for example, user) to construct a valid email address (for example, user@example.com)
when necessary. The rcpthosts
and locals
files are simply lists of domains, one domain per line in the file. The most complex of the four, smtproutes
, is also rather simple. Each line of the file consists of three fields separated by colons. The first field is the domain that needs to be routed this way and the second field is the domain name or IP address (in square brackets) of the server to which matching email must be sent. The third field is the port on the server to connect to, which if not present, defaults to port 25. For example:
somewhere.com:[1.2.3.4]
This line in the file informs qmail that any email sent to an address ending in @somewhere.com
must be forwarded to the IP address 1.2.3.4
. The files smtproutes, rcpthosts
, and locals
can all use prefix-wildcards. A prefix-wildcard is a line that begins with a period, followed by the suffix that must match following the period. For example:
.somewhere.com:mail.isp.com
This line in the smtproutes
file will match email addresses ending in @here.somewhere.com, @there.somewhere.com, @anywhere.somewhere.com
, and so forth, where there is an arbitrary string and a period preceding somewhere.com
. Note that it doesn't match the bare @somewhere.com
. Emails addressed to matching domains are forwarded to mail.isp.com
.
Finally there is the special case, where there is nothing to the left of the first colon as shown in the following example:
:mail.isp.com:1000
This line in the smtproutes
file will send all email to the mail.isp.com
server listening on port 1000
. In the smtproutes
file, the first match is the one that is used, and this line will match anything. As such, it's usually at the end of the file.
There are many more files that qmail looks for in the /var/qmail/control
directory. Explanations of how they work and what they do can be found in the qmail man pages, however, they are generally for more involved configuration tasks and non-basic qmail installations.
Default delivery instructions are part of simple execution.
There are two primary architectural segments of qmail involved in setting up a standard SMTP email server. The first is the set of programs that work together to perform mail deliveries, either locally or remotely, and the second is the set of programs that work together to accept messages via the SMTP protocol.
The programs that work together to perform mail deliveries are: qmail-send, qmail-lspawn, qmail-rspawn
, and qmail-clean
, as well as any program that they spawn to complete their tasks (like qmail-remote, qmail-local, procmail
, etc.). Most of these have corresponding users. In particular, qmail-send
and qmail-clean
operate as the qmails user, and qmail-rspawn
(and qmail-remote)
operate as qmailr. The qmail-lspawn
program runs as root, because it must be able to deliver mail to each user as that user. In any case, all of these programs are spawned by the command qmail-start
. This command takes two optional arguments—a default delivery command and a logging command. To understand exactly how this works, take a look at the most basic of the scripts in the /var/qmail/boot
directory, home:
#!/bin/sh # Using splogger to send the log through syslog. # Using qmail-local to deliver messages to ~/Mailbox by default. exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Mailbox splogger qmail
The first part of this script is fairly straightforward: using the env
command to remove all environment variables before executing qmail-start
, it then sets the PATH
environment variable to make sure that the qmail bin
directory is the first place searched for qmail's binaries. The second part, executing qmail-start
with arguments, requires a little more explanation.
When qmail makes an email delivery, every delivery is made from the perspective of a program running as the receiving user, in the receiving user's home directory. Delivery instructions are treated as if they came from a dot-qmail file, with one delivery instruction per line. From that point onwards, file names are treated as mbox-formated mailboxes, directory names (indicated by ending a file name with a forward-slash (/)) are treated as Maildir-formatted mailboxes, and commands (indicated by starting the line with a pipe symbol (|)) are all located and executed from within the addressed user's home directory. Thus, using a relative file name, such as ./Mailbox
, specifies a file named Mailbox
within the current directory at the time of delivery i.e. the addressed user's home directory.
In this case, the default delivery method is very simple, deliver mail to an mbox-formatted file named Mailbox
in the user's home directory. However, the argument specifying the default delivery method can be more complex. Take, for example, the home+df
file in /var/qmail/boot:
#!/bin/sh # Using splogger to send the log through syslog. # Using dot-forward to support sendmail-style ~/.forward files. # Using qmail-local to deliver messages to ~/Mailbox by default. exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start '|dot-forward .forward ./Mailbox' splogger qmail
Note that because of the rules of shell-script quoting, the first argument to qmail-start
in this case is the full text between the single quotes, or:
|dot-forward .forward ./Mailbox
Note that the single argument is, in fact, two lines. Just as if these lines were in the user's .qmail
file, this causes the dot-forward
command to run first, and if it returns with a code that indicates that the mail has been delivered via instructions in a .forward
file, the delivery is considered complete. On the other hand, if it returns with a code that indicates that the user did not have a .forward
file in his or her home directory, qmail will instead deliver mail to the Mailbox
file, just as it would have if the home
file's delivery instructions were used.
The text after the mail-delivery specification causes qmail-send
to send all logging information to the program specified. In this case, the splogger
program will be run with the argument qmail
. The splogger
program takes the output from qmail-send
, prefixes it with "qmail", and logs it via the standard syslog mechanism. If neither the splogger
command nor any other command is provided as an argument to qmail-send, qmail-send
will send its logging information to standard output (or rather, file descriptor one).
To run this program by hand, simply run your chosen rc
file, as follows:
/bin/sh /var/qmail/rc &
The ampersand at the end ensures that the program executes in the background.
The set of programs that provide SMTP service—receiving SMTP connections (and thus, email) from the network—is organized around qmail-smtpd
. Rather than including basic networking features in the qmail SMTP daemon executable, qmail-smtpd
, qmail pushes that responsibility to a helper program such as tcpserver, inetd, xinetd
, or tcpsvd
, among others. This design decision makes for many useful opportunities. For example, the qmail SMTP service can be tested from the command-line without needing extra software by simply running /var/qmail/bin/qmail-smtpd
. (Note that the DATA phase of the SMTP conversation requires CRLFs rather than simply LFs. The correct line endings can be generated by pressing Ctrl V and then pressing Enter twice.)
Getting qmail-smtpd
to listen to the network requires extra software. Many systems come with either inetd
or xinetd
and they can be configured to run qmail-smtpd
very easily. For example, an inetd.conf
entry for qmail-smtpd
might look like this (all one line):
smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env tcp-env /var/qmail/bin/qmail-smtpd
The current best practice for running qmail-smtpd
is to use the tcpserver
program, also written by the author of qmail, Dr. Bernstein, which is distributed as part of the ucspi-tcp package (http://cr.yp.to/ucspi-tcp.html). It can be used as follows:
tcpserver -u `id -u qmaild` -g `id -g qmaild` \
0 smtp /var/qmail/bin/qmail-smtpd &
This command can be run manually, added to your system's startup commands, or executed using Bernstein's daemontools (http://cr.yp.to/daemontools.html) package. If added to your system's startup commands, the ampersand (&) is critical. The arguments to tcpserver
are straightforward—first, the user and group IDs, then 0
to specify that it will listen to all network interfaces, then smtp
to specify that it will use the SMTP port (25), and finally, the command to be run when a connection is made to that network port.
Standard qmail-smtpd
does not take any run-time arguments; however, its behavior can be modified at run time by using environment variables. In particular, qmail-smtpd
pays attention to the following environment variables:
Environment Variable |
Description |
---|---|
|
The DNS hostname corresponding to the local interface in the connection. |
|
The local IP address in the connection. |
|
The local port number (usually 25 when used with |
|
The DNS hostname of the remote system. |
|
The username responsible for the connection (usually determined using the ident protocol). |
|
The IP address of the remote system. |
|
The port number used by the remote system. |
|
The maximum number of bytes allowed in a message. |
|
The existence of this variable (even if it contains an empty string) allows the sender to relay any email message. The content of this variable is appended to each recipient address. |
Most of these variables (the ones that begin with TCP) are set by the program that handles the network operations. The tcpserver
and tcpsvd
programs set these variables. For programs that do not set these variables (for example, inetd
and xinetd), tcp-env
will set them. The environment variable you will most commonly need to set yourself is RELAYCLIENT
. If this variable is present in the environment, qmail-smtpd
accepts any mail for delivery even if the destination addresses are not in the control/rcpthosts
file. For example, an ISP that relays email from all of its customers generally adds the RELAYCLIENT
variable to qmail-smtpd's
environment, if the connecting client is in its network.
While tcpserver, tcpsvd
, and tcp-env
will set specific environment variables, any other variable (such as RELAYCLIENT)
will generally need to be set using a more generic method. Environment variables can be set in many ways, like using the standard env
utility, the shell's export/setenv
features, and tcprules
files.
Qmail setup as described so far can provide full email service. This setup is, however, rather minimal, and lacks many administrative, maintenance, and troubleshooting features. Because qmail is designed to be modular, these deficiencies are easily remedied with additional programs.
There are a great number of patches available for qmail that provide various sundry features, behavioral tweaks, and even minor bug fixes. There are two schools of thought on how to approach qmail with its plethora of patches. One is to come up with some "official" collection of patches (or just all the patches that sound sufficiently nifty or useful), apply them all, and go from there. The other is to treat qmail more like an efficient mechanism to achieve exactly what needs to be done and no more. This book falls into the latter category. There are several projects that provide "mega"-patches or that package qmail in a way that includes many patches, such as qmailrocks (http://www.qmailrocks.com), Bill Shupp's megapatch (http://www.shupp.org/), Matt Simerson's megatoaster (http://www.tnpi.biz/internet/mail/qmail/qmail.toaster1.2.shtml), and many others.
It is very tempting, particularly when new to qmail, to simply grab a bunch of (neat-sounding) patches and apply them all. This can be a dangerous thing to do unless you know C and SMTP well and can resolve patch conflicts. Even if the patches apply cleanly, the new features may be unnecessary and/or confusing (and may still conflict in terms of their effect). Keep in mind that qmail works just fine without them, and many of them provide features that can be obtained in other ways. Patching is an option, and one that should be used carefully. Every unused feature is memory (and CPU-time) wasted, and a potential source for an unexpected bug or security flaw—many patches have not been as rigorously designed or tested as qmail.
The approach encouraged in this book is one of being pragmatic and efficient (and, consequently, rather minimalist): use patches because the features they provide are necessary, and understand them before applying them. Thus, in this book patch URLs are presented alongside more lengthy explanations of the goal they accomplish and the alternatives and/or downsides.
The most widely recommended method for running qmail uses the daemontools and ucspi-tcp packages, both written by the author of qmail, Dr. Bernstein.
The ucspi-tcp package consists of a set of useful programs for connecting to the network and maintaining simple databases of environment-variable/connection rules. For example, tcpserver
is included as part of ucspi-tcp.
The daemontools package contains the svscan/supervise
programs for running, monitoring, and controlling long-running programs (daemons), and for connecting them to safe logging mechanisms (e.g. multilog
). The default installation of daemontools creates a /service
directory. To control a daemon with svscan
, add a directory for that daemon to the /service
directory. The svscan
program starts up an instance of the supervise
program for each subdirectory of the /service
directory. Each of these directories must contain a shell script named run
that contains all the necessary commands for starting the specific daemon. The run
script must not exit until the daemon it commands exits. When the run
script exits, the directory's supervise
process restarts it, unless the supervise
process has been told not to do so (for e.g. by placing a file named down
in the subdirectory).
The combination of these two packages is a powerful setup for controlling, monitoring, and maintaining a qmail server.
Installing these packages is very simple. The ucspi-tcp package can be installed by simply downloading it (http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz), decompressing it, and running make setup check
in the decompressed source directory.
The daemontools' installation is slightly more complicated.
1. You must create a
/package
directory:
mkdir -p /package
chmod 1755 /package
cd /package
2. Download the daemontools source into this
/package
directory, decompress it, and move into the resulting folders, as follows:
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
tar xzvf daemontools-0.76.tar.gz
rm daemontools-0.76.tar.gz
cd admin/daemontools-0.76
csh -cf '/command/svscanboot &'
Basic use of the tcpserver
program from the ucspi-tcp package has been covered previously. However, the tcpserver
program has many options that are of importance to a well-maintained qmail installation. There are two main areas where tcpserver
shines and is often configured according to the system-administrator's personal preference. The first is in data collection; the second is in setting appropriate environment variables and asserting behaviors based on which remote system connects to tcpserver
.
The tcpserver
program can collect some basic information about the remote server, as described by the possible environment variables in the previous table. However, in many cases, such information is either irrelevant or unnecessary, and the collection of such data can be eliminated to improve connection latency. For example, looking up the remote host's IP address in DNS or attempting to make an ident
query to identify the remote user may not provide much benefit, but does slow down connection attempts. Turning off such queries may improve initial connection latency, if that is a concern.
For example, by default, tcpserver
looks up the remote host's hostname in DNS. If this is unnecessary, giving tcpserver
the -H
flag prevents this, and consequently prevents tcpserver
from providing the TCPREMOTEHOST
environment variable to whatever program it runs (e.g. qmail-smtpd
). Similarly, if ident information is unnecessary, giving tcpserver
the -R
flag will prevent it from performing that query.
The tcpserver
program can also be configured to use a small database (in CDB format) of rules defining when to allow or deny connections and which (if any) environment variables to set, based on the data it knows about the remote host.
The most common method of specifying these connection rules is to create a text file, /etc/tcp.smtp
, in a specific format that is compiled by the tcprules
program into the CDB database used by tcpserver
(e.g. /etc/tcp.smtp.cdb
). The format of a rule in a tcprules
file (such as /etc/tcp.smtp
) is:
matcher : decision , environment-variables (if any)
Connection rules are matched on a first-match-wins basis. For example:
192.168.1.2:deny 192.168.1.:allow,RELAYCLIENT="" =www.example.com:allow,RELAYCLIENT="" =:allow :deny
This rule file would deny all connections from the 192.168.1.2
IP address, but would allow anything else in the 192.168.1.x
IP range to connect and would set the RELAYCLIENT
environment variable for those connections. If the DNS hostname of the remote host is www.example.com
, this file allows that host to connect and sets the RELAYCLIENT
environment variable. Any other host that has a hostname (denoted by the =
sign) is allowed to connect, and finally any other connection attempt (i.e. from a host without a hostname) is rejected.
This rule file can be compiled into a CDB database file as follows:
tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
The tcpserver
program can then be told to use that CDB database by giving it the -x
flag with the name of the CDB
file, for example:
tcpserver -u `id -u qmaild` -g `id -g qmaild` \
-x /etc/tcp.smtp.cdb \
0 smtp /var/qmail/bin/qmail-smtpd
The basic format of a supervise-controlled
service is a folder containing a shell script named run
. This shell script eventually must run the service (daemon) that is to be controlled and must not exit until that daemon does. A good example of what might go into a run
file is the /var/qmail/rc
script built as part of the previously discussed basic qmail install. This script prepares qmail to run, and then runs it. As long as qmail-start
is still running, the script does not exit. Thus, a very simple service folder for the delivery side of qmail is a folder containing that rc
file, renamed run
.
An extension to the previously described basic service-directory format is possible. The extension is to add a folder named log
within the daemon's directory, which contains another shell script named run
. In this extension, the standard output of the first first-level run
file is piped as input to the log
directory's run
file. In this way, the daemon can be stopped and started independently of the logging mechanism, which can be any logging mechanism that accepts standard input, such as splogger
or something similar. An easy, powerful method of logging is the multilog
program (a part of the daemontools package), which saves log output in a crash-resistant, automatically rotating manner with high-precision timestamps.
Ordinarily, qmail-start
uses the logging mechanism specified in the rc
file, usually splogger
. However, if the rc
file (and thus, qmail-start)
is controlled by svscan
, it can be more useful to remove the logging argument from the rc
file. This change causes qmail-send's
log messages to be sent to standard output, which can then be used by svscan's
more flexible logging architecture. There's no benefit from this if you are using the splogger
utility, but more powerful logging tools, such as multilog
, do benefit from the change. The run
file for the qmail-send
service directory might look something like the following:
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Mailbox
A log/run
file for the qmail-send
service directory might look similar to the following:
#!/bin/sh exec setuidgid qmaill multilog t /var/log/qmail/qmail-send/
The beginning of this command, setuidgid qmaill
uses the setuidgid
tool from the ucspi-tcp package. The previous command is essentially equivalent to the following:
exec su qmaill -c 'multilog t /var/log/qmail/qmail-send/'
This is because both switch to a different user (qmaill) before running the rest of the command, but the setuidgid
version is easier to read and type. The reason for using the qmaill user for logging is that it prevents the logs from being altered even if an attacker controls the process generating the logs (qmail-send, in this case).
This same structure can be used for running qmail-smtpd
in a controllable, monitorable fashion. Simply create a directory for it (e.g. /var/qmail/supervise/smtpd
) and create a run
file for it, such as:
#!/bin/sh QUID=`id -u qmaild` QGID=`id -g qmaild` LOCAL=`head -1 /var/qmail/control/me` if [ ! f /var/qmail/control/rcpthosts ]; then echo "Without a rcpthosts file, qmail is an open relay." echo "Open relays are spammer havens." echo "Please use a rcpthosts file." exit 1 fi exec tcpserver -R -l "$LOCAL" -H \ -x /etc/tcp.smtp.cdb \ -u "$QUID" -g "$QGID" \ 0 smtp \ /var/qmail/bin/qmail-smtpd 2>&1
Then create in that directory another directory named log
, and in the log
directory, a run
file such as:
#!/bin/sh exec setuidgid qmail multilog t /var/log/qmail/smtpd/
Once these files are created, telling svscan
to use them to control the service they specify is a two-step process. First, make sure that the run
files are executable:
chmod +x /var/qmail/supervise/smtpd/run
chmod +x /var/qmail/supervise/smtpd/log/run
Then link the daemon's directory into /service
, as follows:
ln -s /var/qmail/supervise/smtpd /service/qmail-smtpd
Wait a few moments, and then run the following to double-check that all is well.
svstat /service/qmail-smtpd
If it started as it should, the output of that command should indicate that the service in question (qmail-smtpd) has been running for a few seconds already. You can perform essentially the same procedure on the qmail-start
service directory, or any other daemon to be controlled by svscan
.
Once svscan
is controlling a folder and the associated daemon, you can command the daemon with the svc
command. For example:
svc -d /service/qmail-smtpd
This will order the qmail-smtpd
service to stop by sending it a TERM signal. Using the -h
flag instead of -d
will cause the service to receive a HUP signal; in the case of qmail-start
, this causes qmail to re-read many of its configuration files. This reread-config-on-HUP is a behavior shared by many UNIX daemons. The -u
flag will cause the service to start again after having been stopped by the -d
flag. The -t
flag, like the -d
flag, also sends a TERM signal. However, unlike the -d
flag, the service is restarted as soon as it exits.
It is important to note that the TERM signal sent by the -t
and -d
flags does not cause all daemons to exit immediately. For example, when qmail-send
receives a TERM signal, it finishes all deliveries currently in progress before exiting—which means that it may take several minutes to exit. To bring a daemon down immediately, use the -k
flag, which sends the un-ignorable KILL signal. Note, though, that while the KILL signal will immediately terminate any process not protected by the kernel, the signal is not propagated to any of the daemon's child processes. Also, the -k
flag alone allows the server to restart once it exits (similar to the -t
flag). Thus, it is often used after the -d
flag has been used first, to terminate a recalcitrant daemon.
Before delving too deeply into further configuration and tailoring of qmail, it is important to understand the basic structure of qmail. Qmail is often referred to as merely a mail server software package. While this may be accurate in one sense, it is more accurate to think of qmail as a mail delivery architecture whose architect has thoughtfully provided a basic implementation of all the components of that architecture.
Qmail is very modular—it consists of a series of simple programs communicating via specific and limited interfaces. Each simple program has a specific and limited task to perform. This architecture allows each component program to be easily replaced or new programs to be inserted between the basic components.
Additionally, this architecture limits the security impact of any one of the components. Each program is further separated from the others, whenever possible, by giving each program a different UNIX user and specific permissions so that it can't affect anything it is not supposed to. Because the communication interfaces are limited, it is significantly more difficult to attack the software and achieve much—attacking a component that does not have enough privileges to do anything other than what it is supposed to do is much less useful for an attacker.
The simplest example is receiving email from the network. The trail of programs in basic qmail is as follows: tcpserver
to qmail-smtpd
to qmail-queue
. The tcpserver
program has two tasks: open up a port to listen to the network, and run qmail-smtpd
as the appropriate user for every connection. Because listening to low ports (such as the SMTP port, 25) requires root permissions, tcpserver
generally runs as root. However, because tcpserver
doesn't attempt to understand the communication, it is very difficult to attack. The qmail-smtpd
program has only two tasks as well: speaking the SMTP protocol sufficiently to receive email messages, and sending these email messages to qmail-queue
. As such, qmail-smtpd
need not do anything with the on-disk queue or the network. This allows qmail-smtpd
to be run as a user with very limited permissions, and also allows qmail-smtpd
to be a much simpler, and easier to verify and debug, program than it would be otherwise, even though it has to interact directly with user (or attacker) input. The qmail-queue
program has only one task—to write messages to the on-disk queue prepended with a Received header. It need not talk to the network, or understand the contents of the messages it writes to disk, making the program simple and easy to verify and thus hard for an attacker to break.
Note that this architecture can be easily extended. The tcpserver
program can execute any program, which can in turn execute qmail-smtpd
as necessary. This might be useful, for example, to make decisions about whether to permit a connection to reach qmail-smtpd
or to set and unset environment variables before qmail-smtpd
is executed. It could even be used to sanitize data before it gets to qmail-smtpd
. Similarly, while qmail-smtpd
normally executes qmail-queue
, it may invoke any program. This program can then execute qmail-queue
as necessary, which might be useful, for example, to filter out email messages that contain viruses.
As another example, the qmail-start
program executes several programs: qmail-send, qmail-lspawn, qmail-rspawn
, and qmail-clean
. Each of these programs has a specific task. qmail-send
must monitor the on-disk queue of mail and route mail appropriately by commanding either qmail-lspawn
or qmail-rspawn
to deliver the message depending on whether the message should be delivered to a local user or a remote user, respectively. Once messages have been delivered, it commands qmail-clean
to remove the message from the queue. Both qmail-lspawn
and qmail-rspawn
receive delivery commands and spawn the necessary number of instances of qmail-local
and qmail-remote
to do the actual delivery. The qmail-remote
program is a simple program that reads an email from standard input, and delivers it to the hosts and recipients specified to it by arguments. It does not have sufficient permissions to read out of the queue itself, and so must be handed the message to deliver. It can even be used alone as follows:
echo message | qmail-remote \
smtp.example.com sender@example.com recipient@example.com
The qmail-local
program is also simple; its task is to read an email from standard input and deliver it to the specified local user, using the procedures detailed in that user's .qmail
files. Like qmail-remote
, it does not have sufficient permissions to read or modify the on-disk queue.
Each of these programs is independent of the others, and relies only on the interface provided to it. By restricting the permissions that each component has, both attacking the system as well as achieving much with a single compromised component is made significantly more difficult. This is the fundamental concept behind the privilege-separation security technique employed by qmail.
The following diagram depicts this description graphically:

In this diagram, each on-disk element is a hexagon, each process is a rectangle, and each separate user-protected domain is a tinted rounded-rectangle (root domains are darker). The arrows indicate the direction email travels through the system. As you can see, the central feature of the qmail architecture is the on-disk queue. Despite its centrality, very few components of qmail need to read or modify the queue.
This chapter has laid out the most fundamental details of qmail: first how to install a minimal qmail server, then convenient means of controlling the qmail server, and finally the basics of the qmail architecture. The fundamental innovation of qmail is its architecture, and as such the rest of this book is devoted, in one way or another, to examining and exploiting the benefits of that architecture. The next chapter talks about the input end of the qmail mail system.
The next two chapters talk about how to operate the queue—first putting messages into the queue and then controlling how messages exit the queue. In essence, the next two chapters focus on the top and bottom halves, respectively, of the qmail architecture.