Release v0.1.0-preview.28: transactional account email
verify / verify (push) Successful in 4m29s

Reviewed source export adds verified TLS mail, encrypted outbox, mailbox verification and password reset protocols. Preserve public ancestry; omit local development history and operational queue. Consumer deployment and inbox delivery proof remain separate.
This commit is contained in:
2026-09-11 04:12:17 -04:00
parent ebcbbf06f5
commit 494b72fa3b
18 changed files with 3175 additions and 47 deletions
+47
View File
@@ -0,0 +1,47 @@
<!-- SPDX-License-Identifier: MPL-2.0 -->
# Encrypted transactional outbox
`mailsqlite.Queue` stores a single-recipient `mail.Message` as authenticated
AES-256-GCM ciphertext. Use a separate 32-byte application-managed secret, kept
out of source control and logs; back it up separately. It may be wrapped in SQLite
only if the wrapping key stays outside the database and is backed up separately.
Identity and expiry
are bound to the ciphertext. Key-derived HMACs support idempotency without storing
plaintext message hashes. Losing the key loses pending message contents.
Call `CreateSchema` inside the application's explicit, versioned migration.
`EnqueueTx` joins a caller-owned transaction, allowing account changes, audit and
mail intent to commit or roll back together. `Enqueue` is a convenience for a
standalone transaction. A message ID belongs to exactly one message/expiry, even
after its payload is cleared. Do not use the queue to authorize recipients.
`ProcessOne` commits a one-minute claim before calling the transport; it never
holds a database writer lock over SMTP. Transports must honor the supplied
deadline (at most 30 seconds). A stale worker cannot acknowledge a newer lease.
Retryable failures back off for 1, 2, 4 and 8 minutes, up to five attempts, only
while the message is valid. Application workers own scheduling and shutdown.
An incorrect key or corrupt payload never reaches SMTP. Such work retains its
ciphertext and retries decoding after five minutes without consuming a delivery
attempt. Restoring the correct key before expiry can recover pending messages.
This is not transparent key rotation: drain the old queue or provide an explicit
migration before changing keys.
Payloads expire within 24 hours and are cleared after terminal delivery results
or expiry. Run `Sweep` periodically even when sending is disabled; each call is
bounded to 100 records. Pending capacity defaults to 1,000 (maximum 10,000).
Safe metadata/deduplication tombstones remain; applications own any later bounded
retention policy and must not reuse purged IDs. Never expose `Recent` publicly.
SMTP acceptance is not inbox delivery. A crash or lost acknowledgement can cause
a retry after the remote server accepted DATA. Stable Message-ID helps diagnose
duplicates but cannot make SMTP exactly-once. Do not use this queue for payments
or another external operation requiring an exactly-once commitment.
Local Go/race/vet tests cover encryption and identity binding, domain rollback,
idempotency, concurrent capacity/claims, lock-free network waits, stale workers,
cancelled acknowledgements, retry bounds, safe diagnostics, expiry and wrong-key
recovery. No real SMTP credential, provider delivery or consumer deployment is
claimed here. [Account verification/reset protocols](../authmail/README.md) are a
separate optional layer, not behavior inferred by the queue.