-
Notifications
You must be signed in to change notification settings - Fork 97
Queue handling in ZoneMTA
ZoneMTA uses LevelDB to store and manage message queue on disk. Mail queue has a few requirements which makes it hard to use a random database backend to store the queue.
- Write heavy. Messages can be queued in large amounts, especially if you are sending to lists
- Light reads. At best you only need to read message data once
- Quick deletes. In a way the message queue acts more like a cache. You write to it, read once and immediately delete. The average lifetime of a value might be just a single second.
- Variable sizes. A queued message might be anything from few hundred bytes to hundred megabytes in size. There is no average message size, so it is hard to optimise for it
ZoneMTA stores message body in chunks where every chunk gets indexed by an incrementing ID value
- message [MSGID] 000001 (64kb chunk)
- message [MSGID] 000002 (64kb chunk)
- message ...
- message [MSGID] nnnnnn (remaining chunk)
Once all body chunks are successfully stored, ZoneMTA adds two additional keys to LevelDB for the message
- message [MSGID] # (indicates that the message exists, stores creation time)
- message [MSGID] * (JSON serialised metadata about the message, including parsed message headers)
Next, ZoneMTA stores recipient data where every recipient has its own key. Recipient keys are ordered by MSGID which in itself is an incrementing value, so messages inserted earlier are ordered before messages added later.
- delivery-zone [ZONE] [MSGID] [email protected]
When ZoneMTA is looking for new messages to deliver, it iterates through recipient list by Zone name
"delivery-zone [ZONE] " ... "delivery-zone [ZONE] ~"
This iteration starts with recipients for the oldest message and continues up to the latest message.
If a recipient is found, ZoneMTA also fetches message metadata from the metadata key. Next the MX for the recipient is resolved and a SMTP connection is initiated. Once SMTP transaction is set up, ZoneMTA fetches all message chunk in the storing order, passes it through SMTP encoder (ensures \r\n line breaks, escapes dots in the beginning of line, adds finishing dot) and pipes it to the receiving SMTP server.
Once a message is delivered ZoneMTA checks if there are any recipient remained for the message and if not, then deletes all message related kesy from the DB.