-
released this
2026-08-20 17:17:07 -05:00 | 31 commits to main since this releaseM3: this server can send mail. Five tools behind
MAIL_SEND_ENABLED, off by default and registering nothing when off, plus themailto:half ofunsubscribe_message— the larger half, since probe 9 found 24 of the 40 senders offering any facility offer only a mailto against 16 one-click.Not live-verified. Probe 6 — does SMTP submission actually deliver — has not run, and a green gate clears nothing here: M2 shipped with 799 passing tests and a
move_messagethat had never worked once. The pass to run is indocs/operations.mdunder M3: the live pass, andMAIL_SEND_ENABLEDstays out of the stack file until it has.The widest grant in the project and not close. Every other one is bounded by the account — a wrong delete is in trash, a wrong rename is renamed back, the unsubscribe POST reaches one endpoint the sender chose. A sent message is in somebody else's mailbox and nothing on this account reaches it.
Added
send_message,reply_message,forward_message,create_draft,send_draft.- Two verdicts on every send. iCloud does not save a Sent copy server-side on SMTP submission, so a send is submit-then-
APPEND: two operations that fail separately and are not atomic.sent: true, saved_to_sent: falseis a real outcome — delivered, with only the user's own record missing — and the note says outright not to resend, because a model reading it as failure mails the recipient twice.send_draftadds a third,draft_removed. reply_allrequiresexpected_recipientsand refuses on mismatch, naming the difference in both directions. It cannot be satisfied without having read the original, which makes a blind reply-all impossible rather than discouraged.- The
mailto:unsubscribe path, riding the existing gate unchanged — sending widens how a sender may be contacted, never who may be. One-click wins whenever both are offered. SMTP_HOST,SMTP_PORT,SMTP_TIMEOUT,SENT_FOLDER,DRAFTS_FOLDER, a preflight check that refuses at boot when those folders are missing or unwritable, and thesmtp/send+tool/sendlog phases.
Security
- An address is syntax, not a value. A recipient carrying CR or LF ends the header and starts another one —
Bcc:being the obvious one to append. The whole C0 range is refused at the boundary, and the refusal never echoes the value back. - A
mailto:unsubscribe's recipient comes from the URI path and nowhere else. RFC 6068 lets the query namecc,bccand a secondto; honouring those would be an open relay wearing an unsubscribe hat. Onlysubjectandbodyare read. send_draftworks only on a message in the drafts folder — submitting a received message would mail it onward to its original recipients.- The Sent folder is proved writable before SMTP is contacted. A refusal arriving after submission is not a gate.
- Bcc is an envelope recipient and never a header, except in a draft, which
send_draftstrips before submitting.
Notes
APPENDUIDgets its own parser. RFC 4315 givesCOPYUIDthree fields andAPPENDUIDtwo, so reusing one would read the wrong field and mint a handle for a UID the server never mentioned. A test pins both shapes.- The Sent copy is located by
APPENDUID, never by searching — probe 4 found the index lags the write. - No retry on an ambiguous SMTP failure: a retry is a second message, not another attempt at the first.
- 1082 tests green (75 new).
Full detail in
CHANGELOG.md.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads