Bulwark had no read-receipt support (JMAP/Stalwart have no native MDN).
End-to-end, client-side, in three parts:
- Request (compose): a toolbar toggle (MailCheck, green when on) sets
Disposition-Notification-To on the outgoing message via the JMAP
"header:<name>:asText" create property. Threaded composer -> page ->
email-store -> client.sendEmail. Default from requestReadReceiptDefault.
- Detect (viewer): reads Disposition-Notification-To case-insensitively from
the parsed headers and shows a banner (green Send / red Ignore) in the
unified notification bar. Hidden in Sent/Drafts/Trash/Junk and once handled.
message/disposition-notification + message/delivery-status report parts are
filtered out of the attachment list.
- Respond (MDN): lib/mdn.ts builds an RFC 8098 multipart/report (text/plain +
message/disposition-notification, UTF-8/base64, localized subject + body).
client.sendReadReceipt uploads the blob, imports it into Sent via
Email/import, then submits with an explicit envelope. Both Send and Ignore
set the $MDNSent keyword (RFC 3503) so no client re-prompts. Behaviour
configurable: ask / always / never.
New: lib/mdn.ts, read-receipt-banner.tsx. Settings (requestReadReceiptDefault,
readReceiptResponse) + UI. All 17 locales.