QMail Overview (Group 6)

The RAIDA messaging surface. Five commands cover the full lifecycle: upload encrypted file fragments, notify the recipient’s beacon RAIDA, poll or peek the beacon for new mail, and download the stored fragments.

Overview

QMail is RAIDA’s store-and-forward messaging service. A message is split into stripes (typically 7 data + 1 parity) and one stripe is uploaded to each of 8 RAIDA servers. The sender then notifies the recipient’s “beacon” RAIDA — a single RAIDA agreed in advance with the recipient — that mail is waiting. The recipient long-polls (ping) or non-blocking-checks (peek) the beacon, and on notification downloads the stripes from the storage RAIDAs and reassembles the message locally.

Current QMail commands are wrapped in the standard 32-byte RAIDA AES-128 packet header. The 48-byte QMail preamble documented below is not that packet header; it is the first 48 bytes of the decrypted request body after the RAIDA header has been parsed.

All five commands are encrypted at the wire level using AES-128 keyed by the caller’s selected coin AN. For upload, tell, ping, and peek, the handler also compares the preamble AN against the stored coin record identified by the preamble. Download currently relies on wire decryption and file/ACL checks.

Per-command wire formats live on the dedicated pages linked from the sidebar: upload, tell, ping, peek, and download.

End-to-end flow

Sender                Storage RAIDAs (x8)              Beacon RAIDA              Recipient
  |                         |                              |                         |
  |-- upload (cmd 70) ----->|  one per RAIDA, parallel     |                         |
  |<-- 250 OK --------------|                              |                         |
  |                         |                              |                         |
  |-------------------- tell (cmd 71) --------------------->|                         |
  |<------------------- 250 OK -----------------------------|                         |
  |                                                        |                         |
  |                                                        |<-- ping (cmd 72) -------|
  |                                                        |    long-poll, parks fd  |
  |                                                        |                         |
  |                                                        |-- 250 + tell blob ----->|
  |                                                        |                         |
  |                         |<------------------------- download (cmd 74) -----------|
  |                         |    one per RAIDA, parallel                             |
  |                         |-- 250 + 256KB page ------------------------------------>|
  |                                                        (reassemble locally)

Universal preamble (48 bytes)

Every QMail request body begins with a 48-byte preamble that authenticates the caller/mailbox identity. The preamble is the same for all five commands and is separate from the RAIDA packet header. Its layout matches qmail_preamble_t in the raidax source:

OffsetSizeFieldDescription
0–1516Challenge12 random bytes followed by a 4-byte big-endian CRC32 of the random bytes. Required for replay protection.
16–238Session IDSet to all zeros for the standard QMail encryption mode.
24–252Coin TypeFixed 00 06 — the QMail/CloudCoin network ID.
261DenominationCaller/mailbox coin denomination (signed; valid range −8 to +6).
27–304Serial NumberCaller/mailbox coin serial number (big-endian). Identifies the AN-bearer being authenticated.
311ReservedWas Device ID. Server reads and ignores — available for future use. Set to 0.
32–4716Authenticity (AN)Caller/mailbox 16-byte AN for this RAIDA. Upload, tell, ping, and peek compare this to the stored AN for the (denom, SN) and reject with ERROR_INVALID_AN on mismatch.

Status codes

QMail uses the standard RAIDA status enum from protocol.h. The codes any QMail handler can return:

DecimalHexSymbolMeaning
80x08ERROR_COIN_NOT_FOUNDThe (denom, SN) in the preamble is not loaded on this RAIDA.
160x10ERROR_INVALID_PACKET_LENGTHBody too short for the command, missing terminator, or declared payload size doesn’t match the body length.
180x12ERROR_WRONG_RAIDAFor tell: no recipient inbox could be written (zero deliveries).
340x22ERROR_INVALID_ENCRYPTIONWire-level decryption failed before the command body was reached. Most often caused by sending a zero-AN preamble or selecting an encryption coin the RAIDA doesn’t hold.
400x28ERROR_INVALID_SN_OR_DENOMINATIONDenomination outside the allowed −8…+6 range.
1690xA9ERROR_PAYMENT_REQUIREDStorage locker payment could not be consumed (empty key or insufficient balance).
1940xC2ERROR_FILESYSTEMServer failed to create a directory, write a file, or arm an inotify watch.
1980xC6ERROR_INVALID_PARAMETERField validation failed (bad coin type, timestamp out of range, stripe count out of range, page beyond end of file, etc.).
2000xC8ERROR_INVALID_ANPreamble AN does not match the server’s stored AN for the (denom, SN).
2020xCAERROR_FILE_NOT_EXISTFor download: the requested (GUID, file_type) is not stored.
2500xFASTATUS_SUCCESSCommand completed successfully.
2540xFEERROR_MEMORY_ALLOCServer allocation failure.

Reserved bytes available for protocol extension

The current QMail wire structures contain the following reserved fields. Each is currently zero-filled by the sender and ignored by the server. They are catalogued here so future protocol extensions know which slots are available without breaking the existing layouts.

StructureFieldBytesNotes
Universal preamblebyte 31 (was Device ID)1Per-request, all five commands. Server reads but ignores.
tell routing header (qmail_tell_req_t)reserved_1[4] at offset 20–234Sits between total_file_size and client_timestamp.
tell routing headerreserved_2[1] at offset 471Tail of the 48-byte routing header.
tell recipient entry (qmail_address_entry_t)reserved[8] at offset 24–318 per recipientOne entry per recipient (To/CC/BCC). Multiplies with recipient count.
tell file header (qmail_file_header_t)reserved[5] at offset 59–635 per emailTail of the manifest header. Bytes 57 (edit_sequence) and 58 (parity_algo) of the same region used to be reserved and now carry defined meanings. Pass-through — the recipient reads these bytes verbatim through tell → ping → download.
tell file manifest entryreserved[2] at entry offset 2–32 per fileOne per manifest entry (body + N attachments). Pass-through, sits between file_flags and original_size.
tell file header (qmail_file_header_t)manifest_flags bits 2–7 at offset 566 bits per emailBits 0 (footer_removed) and 1 (crc32_present) are defined. Bits 2–7 are available for future flags.
download request (qmail_download_req_t)bytes_per_page at offset 321Server hard-codes 256 KB pages and ignores this byte.
ping/peek response array header (qmail_response_array_header_t)reserved[5] at offset 3–75Sits between total_tells and the first 64-byte file-header that follows.

Largest contiguous pass-through region today: the 8 bytes per recipient in qmail_address_entry_t.reserved[8], plus the per-email 5-byte tail of the manifest header (file_header.reserved[59..63]). The address-entry reserved bytes are beacon-local (the beacon validates the address record); the manifest-header tail is pass-through and reaches the recipient verbatim.

Defined fields formerly listed as reserved. File-header bytes 57 (edit_sequence) and 58 (parity_algo) used to be part of the manifest-header reserved tail. They now carry sender-controlled meanings — see the tell page for details.

Legacy footer migration note. Pre-manifest .tell files on disk include an 18-byte recipient footer (tag 0x50, length 16, recipient locker). Current manifest v1 records have no footer. Implementations may strip the legacy footer when migrating pre-manifest .tell files; new code should not emit, parse, or expect a footer on the wire.