# Approved email identity and incoming reply matching

Phase 3 milestone 15, implemented locally on 2026-10-14. Web, iOS and Android can inspect the final identity sealed by a separate administrator's approval. **Sending remains disabled.** No provider connection, dispatch route, automatic attempt, queue or retry was added.

## Sealing an approval

Preparation retains its existing `message_format` preview. Approval adds a separate optional `delivery_format` containing a new `<pb-mail.…@sender-domain>` Message-ID, UTC Date, exact plain-text UTF-8 MIME bytes, size and SHA-256 digest. The date is the sealing/origination time, not a submission or delivery timestamp. The subject, addresses, body and reply context come from the reviewed snapshot. Preview bytes are preserved.

The format, approval history and outgoing identity index commit together. An identical approval retry returns the saved result; reads never regenerate identifiers or dates. Preparing and approving a new revision creates a different identity. Older approval history remains intact. Existing approvals are not backfilled with invented identities: prepare and approve a fresh revision when a final identity is needed.

`outgoing_messages` indexes each final Message-ID against exactly one approval, outbound record, version, sender, recipient and mailbox identity. Mailbox identity includes host, port, username, address and folder but excludes passwords. Preview IDs are not indexed. None of these records alone establishes that an email was sent.

## Incoming replies

The importer parses raw `References` and `In-Reply-To` headers with a conservative ASCII message-ID subset. It accepts one References field with up to 20 identifiers and one In-Reply-To identifier; valid folded headers are allowed. Duplicate fields, invalid tails, excessive chains and ambiguous direct parents prevent grouping. Incoming Message-ID provenance likewise requires a single supported raw value.

A final outgoing identifier can anchor a conversation only when all of these agree:

- The saved mailbox identity and incoming sender match the indexed mailbox and recipient.
- Approval history, attempt and index refer to the same outbound revision.
- The exact attempt snapshot equals the approved snapshot, including the final format and matching byte digest/size.
- The attempt records server acceptance or an uncertain outcome, or is durably in `handing_off` without an outcome. An uncertain handoff can plausibly have submitted bytes; it is not proof of delivery.
- All known incoming/outgoing reference anchors agree on one email conversation and correspondent. Identifier collisions, different senders, different threads and known outgoing references without submission evidence prevent fallback to an earlier incoming anchor.

Preparation, approval alone, simulations, untouched claims, blocked attempts, rejection and recorded non-submission cannot supply outgoing submission evidence. Unknown IDs do not supply evidence. The index and retained incoming queries are bounded, and overflow prevents grouping.

The importer locks the candidate conversation and refreshes the evidence before attaching a reply. Valid matches reopen the conversation, preserve its draft and increment its version, making any previous outbound approval stale. Conflicting evidence creates a separate conversation with a fixed review warning. Import and checkpoint remain atomic. Historical submitted identities still work after later drafts or approvals.

Email headers and From addresses are untrusted grouping hints, not authentication or commercial authorization. Importing a reply never marks an attempt delivered, changes its protocol outcome, clears uncertainty, authorizes a resend or confirms an order.

## Review and migration

Web/native approval and attempt views label the final identity as sealed, with sending disabled, and provide literal source inspection. Existing preparation previews remain separately visible.

Back up and migrate to `1b84c6e25009`. The migration adds one empty table and does not rewrite accounts, passwords, business data, old snapshots or attempt history. A downgrade refuses to discard populated identity records. The local preview and development databases were backed up and migrated with all 57 existing tables unchanged; see [validation](VALIDATION.md).

Local checks cover SQLite/PostgreSQL, approval retry stability, received replies, uncertain handoffs, historical identity reuse, malformed and conflicting references, evidence refresh after locking, migration preservation, restricted runtime grants, browser phone-width inspection, client type checks, web compilation and iOS/Android exports. These do not establish live mailbox/provider interoperability, hosted readiness or physical-device behavior.

## Next

The [application handoff core and isolated rehearsal](EMAIL-HANDOFF.md) now connect sealed formats to the actual attempt ledger and administrator recovery rules as milestone 16. Live dispatch remains unavailable and provider tests remain deferred. Production transport, scheduling, private activation, hosted operations and explicitly authorized live checks remain later work. The earlier script-only prototype remains a separate laboratory and is not a production worker.
