QMail Services (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.

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)

Command reference

Each command has its own page documenting the wire format byte-by-byte, status codes, server-side behavior, reserved fields, and example request/response layouts.

Code Name Purpose Server function
70uploadStore one stripe of one file under a 16-byte GUID.cmd_qmail_upload2
71tellNotify a recipient’s beacon RAIDA that mail is waiting.cmd_qmail_tell2
72pingLong-poll the beacon for new tell notifications.cmd_qmail_ping2
73peekNon-blocking check for tells newer than a timestamp.cmd_qmail_peek2
74downloadFetch one 256 KB page of a stored file.cmd_qmail_download2

Naming note

The on-disk server function names still carry a 2 suffix (cmd_qmail_upload2, cmd_qmail_tell2, etc.) for historical reasons — the original v1 commands at codes 60–64 have been removed. The active command codes are 70–74 and are what this documentation refers to as upload, tell, ping, peek, and download. If you see 2-suffixed names in raidax source, they are the same commands.

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_v2_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_v2_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_v2_file_header_t)reserved[13] at offset 51–6313 per emailPass-through blob shared by tell → ping → download. Recipient sees these bytes verbatim.
download request (qmail_download2_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.

The largest contiguous reserved region is qmail_v2_file_header_t.reserved[13], because it is part of the pass-through blob that the sender writes once and the recipient reads back through the tell → ping → download chain. That makes it the natural place to add per-email metadata (file-type masks, attachment counts, future ACL fields).