The qmail source distribution includes nine PIC.* files.
Collectively,
these files provide an excellent picture
of how qmail
processes incoming messages.
When configuring qmail for specific requirements
--[such as the Radio Email
project in West Africa]--
it is essential to understand this picture,
with a clear idea about what decisions qmail makes at each
stage of processing.
This page represents an effort to synthesize the PIC.* files
from another perspective, and describe an overall flow chart
for qmail.
This chart is broken down into three sections:
Local vs. remote delivery.
Remote delivery.
Local delivery.
All in glorious ascii art!
qmail can accept a message for delivery from any of several sources:
Once a message has been accepted, the first decision qmail must make (by qmail-send), is whether to queue the message for local or remote delivery. In order to make this decision, it examines the recipient address:
someuser@somehost
This address is broken down into two main parts,
according to what appears before and after the @
symbol:
USER=someuser HOSTNAME=somehost
qmail then applies the tests and decision tree as outlined in the following diagram:
+----------------------------+ | control/locals | | | | match for HOSTNAME? | YES | |----------------------->| +----------------------------+ | | | | NO | | | V | +----------------------------+ | | control/virtualdomains | | | | | | match for USER@HOSTNAME? | YES | | match for HOSTNAME? |----------------------->| +----------------------------+ | | | | NO | | | V V +============================+ +============================+ ! REMOTE DELIVERY ! ! LOCAL DELIVERY ! +============================+ +============================+
Here we see that qmail first checks the control file locals, to find any match for HOSTNAME. If found, it passes the message to qmail-lspawn for local delivery.
Otherwise, qmail tests the control file virtualdomains. Here it looks for an entry matching the form:
USER@HOSTNAME:localuser
or:
HOSTNAME:localuser
If found, it passes the message for local delivery to qmail-lspawn as an extension address of the form:
localuser-USER
(Hopefully this diagram makes it clear why virtual domains should not also be entered into the control/locals control file.)
Otherwise, qmail decides the message should be passed to qmail-rspawn for remote delivery.
Once a message has been queued for remote delivery, qmail takes a decision path as outlined in this diagram:
+----------------------------+ | control/smtproutes | | | | match for HOSTNAME? | YES (IP) | |----------------------->| +----------------------------+ | | | | NO | | | V | +----------------------------+ | | | | | dnsmx HOSTNAME? | YES (IP) | | |----------------------->| +----------------------------+ | | | | NO | | | | V | +----------------------------+ | | | | NO | SMTP delivery IP, success? | |<----------------------------| | | +----------------------------+ | | | | YES | | V V +============================+ ======== ! control/queuelifetime ! done! ! ! ======== ! defer delivery or ! ! BOUNCE ! +============================+
Here qmail-remote first checks the smtproutes control file for any entry where HOSTNAME matches the DOMAIN expression of the form:
DOMAIN:relayhost
There are several ways HOSTNAME may match DOMAIN through
wildcard
expressions,
including:
:relayhost
In this case, all remote-bound mail will be attempted to relayhost.
Otherwise, if no match in smtproutes is found, qmail-remote will perform DNS lookups for a mail-exchange (MX) record for HOSTNAME.
qmail-remote will make repeated attempts to deliver the message to the remote host, until the time in control/queuelifetime has been reached. Then, if the message has still not been delivered, it is bounced back to the sender.
Note: once qmail has made its decision to queue for remote delivery, that's it. The message is queued for remote delivery. Sometimes this isn't what you want. For example, you forgot (or mispelled) an entry in control/locals for a domain that should be considered local.
What to do? You could just wait for the message to bounce. Instead:
Fix control/locals with the correct entry for HOSTNAME.
Make a temporary entry in control/smtproutes, forcing delivery for HOSTNAME to localhost.
Give qmail-send a SIG-ALRM:
# svc -a /service/qmail-send
After the queue has cleared, remove the temporary entry from control/smtproutes.
Once a message has been queued for local delivery, qmail executes a decision tree similar to the following:
+----------------------------+ | /var/qmail/users/cdb | | | | match for USER? | YES +============================+ | |----------->! setup for qmail-local ! +----------------------------+ +============================+ | | | NO | | | V | +----------------------------+ | | /etc/passwd | | | | V | account for USER? | YES +-----------------------------+ | uid USER nonzero? |----------->| ~USER exists? | +----------------------------+ | ~USER owned by uid USER? | | +-----------------------------+ | NO | | | | YES | NO V V : +----------------------------+ +-----------------------------+ | /var/qmail/alias | | ~USER | | | | | | if USER: | | if USER: | | .qmail-USER? | | .qmail? | | .qmail-default? | | .qmail-default? | | default delivery? | | default delivery? | | | | | | if USER-EXT: | | if USER-EXT: | | .qmail-USER-EXT? | | .qmail-EXT? | | .qmail-USER-default? | | .qmail-EXT-default? | | .qmail-default? | | .qmail-default? | | default delivery? | | default delivery? | +----------------------------+ +-----------------------------+ | | | | | NO | YES YES | | NO | \----------------------/ | | | | V V V ========== =========== +============================+ BOUNCE deliver ! control/queuelifetime ! ========== =========== ! ! ! defer delivery or ! ! BOUNCE ! +============================+
First qmail-lspawn checks the special qmail-users
database in /var/qmail/users/cdb.
This database provides a fine-grained mechanism for routing
local mail deliveries,
as an alternative to the standard /etc/passwd mechanism.
(We don't discuss it further here; see the man page
for qmail-users(5) for more information.)
Then qmail checks /etc/passwd for an account matching USER. If found, there are several additional constraints:
qmailp
Once these constraints have been met,
control is passed to qmail-local for the delivery.
Here qmail searches for delivery instructions in the user's home directory according
to the dot-qmail
conventions,
and according to whether the address has an extension,
in the .qmail files as shown.
If no dot-qmail
delivery instructions are found,
qmail attempts the default delivery instructions as provided
to qmail-start in the qmail-send run
script.
If for some reason the message to USER is undeliverable, qmail will keep trying until the time in control/queuelifetime has expired. Some of the conditions that may temporarily prevent delivery include:
If the faulty conditions are corrected, the mail will be delivered on the next attempt.
If no account for USER was found in /etc/passwd,
or if USER has a uid=0,
then control is passed to qmail-local
to attempt delivery to the special alias
user.
Again, the dot-qmail
conventions are followed,
now according to the .qmail files found within
/var/qmail/alias.
The special alias
user is qmail's user of last resort.
If a message is not deliverable to alias
,
then the message is considered undeliverable.
The bounce
you hear next is the process starting all over again
from the top,
to return the message back to the sender...
Copyright © 2002, 2003, Wayne Marshall.
All rights reserved.
Last edit 2003.12.31, wcm.