Каждое сообщение добавляется в центральный каталог
очереди сообщений с помощью qmail-queue. Qmail-queue вызывается по
необходимости, обычно программой qmail-inject для локально составленных
сообщений, qmail-smtpd - для сообщений, полученных по SMTP, qmail-local - для
пересланных сообщений и qmail-send - для возвращенных сообщений Каждое
сообщение затем отправляется программой qmail-send совместно с qmail-lspawn и
qmail-rspawn и удаляется из очереди программой qmail-clean. Эти 4 программы -
демоны.
Структура очереди сообщений
Каждое сообщение из
очереди имеет свой уникальный номер (пусть 457). Центральная очередь
организована в виде набора каталогов, каждый из которых может содержать файлы,
связанные с сообщением 457:
Mess/457: сообщение Todo/457: конверт:
откуда сообщение пришло и куда отправляется Intd/457: конверт, создается
qmail-queue Info/457: адрес отправителя конверта, после предварительной
обработки Local/457: локальные адреса получателя конверта, после
предварительной обработки Remote/457: удаленные адреса получателя конверта,
после предварительной обработки Bounce/457: постоянные ошибки
доставки
Стадии, в которых может находиться сообщение. '+' означает,
что файл существует; '-' не существует, '?' может как существовать, так и нет.
Чтобы добавить сообщение в очередь,
qmail-queue сначала создает файл в отдельном каталоге, pid/, с уникальным
именем. Файловая система назначает этому файлу номер inode. Qmail-queue
переименовывает pid/whatever как mess/457, перемещая сообщение в состояние S2,
записывает сообщение в mess/457. Далее создает intd/457, перемещая сообщение в
состояние S3, и записывает необходимую информацию в intd/457.
Наконец,
qmail-queue создает новую ссылку, todo/457, для intd/457, - это стадия S4. В
этот момент сообщение успешно поставлено в очередь, и qmail-queue покидает его
для дальнейшей обработки программой qmail-send.
Qmail-queue включает
24-часовой таймер до доступа к любому файлу и "совершает
самоубийство", если данное время истекает.
Как сообщение из
очереди проходит предварительную обработку
Как только сообщение было
поставлено в очередь, qmail-send должен решить, какие адресаты являются
локальными и какие удаленными. Когда qmail-send замечает файл todo/457, он
узнает, что сообщение 457 находится в состоянии S4. Qmail-send удаляет info/457,
local/457 и remote/457, если они существуют. После чего, он прочитывает
todo/457, создает info/457, возможно local/457 и возможно remote/457, после чего
удаляет intd/457. Наконец, qmail-send удаляет todo/457, и сообщение попадает в
состояние S5. К этому моменту сообщение удачно прошло предварительную обработку
перед дальнейшей отправкой.
Как сообщения
доставляются
Сообщения в состоянии S5 управляются следующим образом.
Каждый адрес в local/457 и remote/457 помечается как NOT DONE или
DONE.
DONE: сообщение было успешно доставлено или последняя попытка
доставки встречается с постоянным отказом, другими словами, qmail-send не будет
больше совершать попыток доставки данного сообщения.
NOT DONE:
qmail-send будет пытаться доставить данное сообщение в будущем.
Если
попытка доставки сообщения сталкивается с постоянным отказом, qmail-send сперва
добавляет заметку в bounce/457, создавая этот файл при необходимости, после чего
помечает данный адрес как DONE.
Qmail-send может обрабатывать bounce/457
в любое время следующим образом: добавляет новые заметки об отказах; удаляет
bounce/457. Когда все адреса в local/457 помечены как DONE, qmail-send
удаляет local/457 (аналогично для remote/457).
После обработки всех
адресов из local/457 и remote/457, qmail-send устраняет сообщение следующим
образом. Сначала, если существует bounce/457, qmail-send управляет им как
описано выше. Как только bounce/457 точно обработан, qmail-send удаляет info/457
и mess/457, помещая сообщение в состояние S1.
Очистка
очереди
Если происходит крах системы в то время, как qmail-queue
пытается поставить сообщение в очередь или qmail-send устраняет сообщение, оно
может быть потеряно в состояниях S2 или S3.
Когда qmail-send видит
сообщение в состояниях S2 или S3, причем mess/457 'старше' 36 часов, qmail-send
удаляет intd/457, если он существует. Аналогично, когда qmail-send, видит
файл в каталоге pid/, который 'старше' 36 часов, также удаляет
его.
Чистки очереди не являются необходимыми, если крах системы
происходит в то время, как qmail-send доставляет сообщение. Хуже ситуация, когда
сообщение доставляется дважды (это может случиться, например, если
SMTP-соединение рушится как раз перед моментом оповещения сервером об успешном
получении сообщения).