# Account mail protocols `authmail` provides optional verification, confirmed address changes and password reset. It does not deliver mail directly or own the application router. Use `authsqlite.Store.AccountMail` for an adapter sharing the identity database and encrypted transactional outbox. Call `MigrateMail` explicitly and require its independent schema version before enabling these routes. Base identity schema 11 and historical commerce records are unchanged; existing mailboxes start unverified. ## Operations - Verification requires a current unrestricted account session and confirmation at its existing canonical mailbox. Reading/inspecting a link does not verify it. - Address change requires the current password and that session, then separate confirmation at both current and proposed mailboxes. The current address stays authoritative until both confirm. No passkey-approval boolean bypass exists. A future passkey-only path needs a separately bound fresh-approval protocol. - Password reset is available only through the current verified mailbox of an active, fully registered account. Request results are generic for unknown, unverified, inactive, malformed and account-throttled addresses. A reset creates no login, removes no passkey/recovery code and bypasses no existing MFA policy. Tokens use 32 random bytes and purpose-bound SHA-256 digests, expire in 15 minutes, and work once. Requests bind the user ID, canonical address, profile revision and current password digest; address/verification requests also bind the real acting session. A replacement request invalidates the previous link for that purpose. Already-in-flight older mail may still arrive; an invalidated token cannot act. The SQLite adapter rechecks authority and identity under its writer lock, including fresh time after waits/password hashing. A changed password, profile, address, status or acting session rejects stale requests. Address uniqueness is checked again at final confirmation. Old-address invitations are revoked, not moved; new-address invitations still need normal token/authority checks to be accepted. Existing memberships, ownership and purchase snapshots retain the immutable user. Successful reset/address changes revoke sessions, pending ceremonies, enrollment and recovery grants, and outstanding account-mail requests. Mailbox changes notify both addresses; resets notify the current mailbox. Account changes, notifications and secret-free audits commit atomically. Delivery capacity/audit failures roll everything back, leaving valid tokens retryable until their original expiry. Per-account requests are limited to one per minute and five per hour across these purposes. At most one pending request per account/purpose remains. Applications must also impose IP and password-hashing concurrency limits and handle anonymous request responses without disclosing per-account operational failures. ## Required application boundaries - Use a configured HTTPS origin and fixed route paths. Never build links from a request Host header. `Composer` customizes reviewed plain-text copy, not security state, sender, recipient, headers or editable executable templates. - Render a deliberate confirmation/reset form; only POST consumes a token. Keep strict same-origin/CSRF protection and private/no-store responses. Prefer `TokenInFragment` so the browser transfers the code into the deliberate POST without placing it in HTTP/proxy request targets. Native forms can require a same-origin referrer policy to retain a usable Origin header; fragments are never included in referrers. Script-only flows can use no-referrer. Do not weaken origin validation to accept opaque/null origins, and never allow link scanners or GET requests to change account state. - Exclude tokens, query strings, message bodies, addresses, passwords and SMTP credentials from logs/telemetry. Restrict token-bearing pages and avoid external analytics/resources. Debug redaction does not make structured serialization safe. - Return anonymous request responses consistently, independent of eligibility or SMTP acceptance. Run SMTP through the bounded outbox worker, not in the request. - After reset/change, clear the browser's old session and return to normal login. Preserve the application's passkey/MFA checks; mailbox control is not an owner recovery grant. Keep printed/owner-assisted recovery separate. - Existing Stripe receipts/billing emails are financial snapshots, not canonical login identifiers. Do not rewrite them as part of an account email change. The design follows the applicable OWASP guidance on [password reset](https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html) and [registered-email changes](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#changing-a-users-registered-email-address). This is not a claim of a completed application security audit. Local tests cover both confirmation orders, replay/expiry, generic reset requests, credential/session races, competing resets, address conflicts, stable ownership, retained factors, invitation handling, rate limits, restart and transactional migration/audit/outbox rollback. The account packages and mail/outbox suites pass; focused races and vet pass. The preview28 consumer dogfood also covers native HTTP/UI integration and real BHS inbox verification/reset/both-mailbox flows. Each application must still verify its own sender configuration, recipient delivery and recovery operations; local provider proof is not an assurance of external spam placement or mail reputation.