debian/rules: Use `git' potty wrapper.
[qmail] / INTERNALS
CommitLineData
2117e02e
MW
11. Overview
2
3Here's the data flow in the qmail suite:
4
5 qmail-smtpd --- qmail-queue --- qmail-send --- qmail-rspawn --- qmail-remote
6 / | \
7qmail-inject _/ qmail-clean \_ qmail-lspawn --- qmail-local
8
9Every message is added to a central queue directory by qmail-queue.
10qmail-queue is invoked as needed, usually by qmail-inject for locally
11generated messages, qmail-smtpd for messages received through SMTP,
12qmail-local for forwarded messages, or qmail-send for bounce messages.
13
14Every message is then delivered by qmail-send, in cooperation with
15qmail-lspawn and qmail-rspawn, and cleaned up by qmail-clean. These four
16programs are long-running daemons.
17
18The queue is designed to be crashproof, provided that the underlying
19filesystem is crashproof. All cleanups are handled by qmail-send and
20qmail-clean without human intervention. See section 6 for more details.
21
22
232. Queue structure
24
25Each message in the queue is identified by a unique number, let's say
26457. The queue is organized into several directories, each of which may
27contain files related to message 457:
28
29 mess/457: the message
30 todo/457: the envelope: where the message came from, where it's going
31 intd/457: the envelope, under construction by qmail-queue
32 info/457: the envelope sender address, after preprocessing
33 local/457: local envelope recipient addresses, after preprocessing
34 remote/457: remote envelope recipient addresses, after preprocessing
35 bounce/457: permanent delivery errors
36
37Here are all possible states for a message. + means a file exists; -
38means it does not exist; ? means it may or may not exist.
39
40 S1. -mess -intd -todo -info -local -remote -bounce
41 S2. +mess -intd -todo -info -local -remote -bounce
42 S3. +mess +intd -todo -info -local -remote -bounce
43 S4. +mess ?intd +todo ?info ?local ?remote -bounce (queued)
44 S5. +mess -intd -todo +info ?local ?remote ?bounce (preprocessed)
45
46Guarantee: If mess/457 exists, it has inode number 457.
47
48
493. How messages enter the queue
50
51To add a message to the queue, qmail-queue first creates a file in a
52separate directory, pid/, with a unique name. The filesystem assigns
53that file a unique inode number. qmail-queue looks at that number, say
54457. By the guarantee above, message 457 must be in state S1.
55
56qmail-queue renames pid/whatever as mess/457, moving to S2. It writes
57the message to mess/457. It then creates intd/457, moving to S3, and
58writes the envelope information to intd/457.
59
60Finally qmail-queue creates a new link, todo/457, for intd/457, moving
61to S4. At that instant the message has been successfully queued, and
62qmail-queue leaves it for further handling by qmail-send.
63
64qmail-queue starts a 24-hour timer before touching any files, and
65commits suicide if the timer expires.
66
67
684. How queued messages are preprocessed
69
70Once a message has been queued, qmail-send must decide which recipients
71are local and which recipients are remote. It may also rewrite some
72recipient addresses.
73
74When qmail-send notices todo/457, it knows that message 457 is in S4. It
75removes info/457, local/457, and remote/457 if they exist. Then it reads
76through todo/457. It creates info/457, possibly local/457, and possibly
77remote/457. When it is done, it removes intd/457. The message is still
78in S4 at this point. Finally qmail-send removes todo/457, moving to S5.
79At that instant the message has been successfully preprocessed.
80
81
825. How preprocessed messages are delivered
83
84Messages at S5 are handled as follows. Each address in local/457 and
85remote/457 is marked either NOT DONE or DONE.
86
87 DONE: The message was successfully delivered, or the last delivery
88 attempt met with permanent failure. Either way, qmail-send
89 should not attempt further delivery to this address.
90
91 NOT DONE: If there have been any delivery attempts, they have all
92 met with temporary failure. Either way, qmail-send should
93 try delivery in the future.
94
95qmail-send may at its leisure try to deliver a message to a NOT DONE
96address. If the message is successfully delivered, qmail-send marks the
97address as DONE. If the delivery attempt meets with permanent failure,
98qmail-send first appends a note to bounce/457, creating bounce/457 if
212b6f5d
MW
99necessary; then it marks the address as DONE. Note that bounce/457 is
100not crashproof.
2117e02e
MW
101
102qmail-send may handle bounce/457 at any time, as follows: it (1) injects
103a new bounce message, created from bounce/457 and mess/457; (2) deletes
104bounce/457.
105
106When all addresses in local/457 are DONE, qmail-send deletes local/457.
107Same for remote/457.
108
109When local/457 and remote/457 are gone, qmail-send eliminates the
110message, as follows. First, if bounce/457 exists, qmail-send handles it
111as described above. Once bounce/457 is definitely gone, qmail-send
112deletes info/457, moving to S2, and finally mess/457, moving to S1.
113
114
1156. Cleanups
116
117If the computer crashes while qmail-queue is trying to queue a message,
118or while qmail-send is eliminating a message, the message may be left in
119state S2 or S3.
120
121When qmail-send sees a message in state S2 or S3---other than one
122it is currently eliminating!---where mess/457 is more than 36 hours old,
123it deletes intd/457 if that exists, then deletes mess/457. Note that any
124qmail-queue handling the message must be dead.
125
126Similarly, when qmail-send sees a file in the pid/ directory that is
127more than 36 hours old, it deletes it.
128
129Cleanups are not necessary if the computer crashes while qmail-send is
130delivering a message. At worst a message may be delivered twice. (There
131is no way for a distributed mail system to eliminate the possibility of
132duplication. What if an SMTP connection is broken just before the server
133acknowledges successful receipt of the message? The client must assume
134the worst and send the message again. Similarly, if the computer crashes
135just before qmail-send marks a message as DONE, the new qmail-send must
136assume the worst and send the message again. The usual solutions in the
137database literature---e.g., keeping log files---amount to saying that
138it's the recipient's computer's job to discard duplicate messages.)
139
140
1417. Further notes
142
143Currently info/457 serves two purposes: first, it records the envelope
144sender; second, its modification time is used to decide when a message
145has been in the queue too long. In the future info/457 may store more
146information. Any non-backwards-compatible changes will be identified by
147version numbers.
148
149When qmail-queue has successfully placed a message into the queue, it
150pulls a trigger offered by qmail-send. Here is the current triggering
151mechanism: lock/trigger is a named pipe. Before scanning todo/,
152qmail-send opens lock/trigger O_NDELAY for reading. It then selects for
153readability on lock/trigger. qmail-queue pulls the trigger by writing a
154byte O_NDELAY to lock/trigger. This makes lock/trigger readable and
155wakes up qmail-send. Before scanning todo/ again, qmail-send closes and
156reopens lock/trigger.