Marty Sampson.aiAI, applied
Systems explainer · pinned-source inspection · no mailbox run

Who owns an email before it is sent?

An agent can read a message and save a draft without sending anything. That distinction sounds simple, but it becomes useful only when each stage names the state it owns, the external effect it can cause, and the evidence needed before moving forward.

Methods note

This article inspects Cloudflare’s Agentic Inbox repository at commit 48039bb…4c80 and uses a fictional message. The repository was not installed or run. No account, mailbox, domain, model, attachment, or email delivery was used.

One message, several owners

Imagine an inbound email called Request #104 with a harmless text attachment named requirements.txt. The sequence below is an original teaching map reconstructed from pinned source. It is not a runtime trace.

  1. 01ReceiveEmail Routing invokes the Worker’s email handler with a raw message stream.
  2. 02Store attachment bytesThe inspected inbound path writes attachments to R2 under keys derived from message, attachment, and sanitized filename identities.
  3. 03Persist message stateA mailbox Durable Object then stores message, folder, thread, header, and attachment-metadata rows in SQLite.
  4. 04Read into contextThe browser, email agent, or MCP tools can retrieve selected mailbox and thread state.
  5. 05DraftA reply becomes a separate message record in the Drafts folder. It is durable, but it is not delivered.
  6. 06ConfirmA person or calling workflow decides whether the exact recipient, subject, body, and attachments should cross the send boundary.
  7. 07Send requestA send tool verifies or transforms the body, then calls the outbound email binding; after that succeeds, the inspected tool path writes a Sent-folder record.

The storage boundary is not the authorization boundary

The pinned repository creates separate Durable Object identities for mailboxes and stores email state in each object’s SQLite database. Attachment metadata is stored with the email records, while attachment bytes are stored separately in R2. That is a useful state partition, but it does not mean each signed-in person is authorized for only one mailbox.

The repository README explicitly says that anyone who passes the shared Cloudflare Access policy can access every mailbox in the application, including through its MCP endpoint. It describes Cloudflare Access as the single trust boundary and says there is no per-mailbox authorization. Storage isolation and user authorization answer different questions.

A draft is evidence of writing, not evidence of sending

The inspected agent surface exposes tools for reading messages, searching, creating drafts, moving messages, and discarding drafts. Its agent-specific tool set does not include a send tool, and its default prompt says the operator reviews and sends drafts from the interface. Draft updating exists in the shared tool path and is exposed by the separate MCP surface, which also exposes send operations whose descriptions tell a client to call them only after confirmation.

That wording is useful guidance, not a durable approval record by itself. In the inspected schema, there is no confirmation snapshot binding an approver to an exact recipient, subject, body, attachment set, and send request. A system that needs that assurance would have to record and enforce it explicitly.

StateWhat existsWhat has happenedEvidence question
ReceivedParsed message plus mailbox identityInbound delivery reached the handlerWas failure retried, rejected, or silently accepted?
PersistedSQLite message row and attachment metadata; R2 objects for attachment bytesMailbox state changedCan partial failure leave metadata and objects out of sync?
DraftedA Drafts-folder message linked to the original/threadNo outbound deliveryCan the reviewer inspect the exact proposed payload?
ConfirmedA decision in the surrounding workflowStill no send merely because prose says “confirm”Is the decision bound to immutable content and actor identity?
Accepted for sendAn outbound provider responseThe external send call returned successfullyDoes this prove provider acceptance only, or recipient delivery?
Recorded as sentA Sent-folder recordLocal state records the successful send pathCould provider success and local persistence diverge?

Two return paths matter

Draft refused

Return to composition

In the inspected update path, failed body verification occurs before the old draft is deleted. Replacement then deletes the old draft before creating the new one, so a later write failure is a separate partial-failure case—not an atomic preservation guarantee.

Send failed

Return with an error

An error response is not proof of either delivery or non-delivery; reconcile provider evidence before retrying. Provider acceptance followed by a failed local Sent-folder write leaves uncertain local record state and is not a safe automatic retry. The inspected source shows an order; this article does not claim that failure was executed.

Use the map on another system

For every transition, record the state owner, stable identity, permitted writer, external effect, confirmation binding, failure return path, and evidence. A downloadable blank worksheet keeps those questions separate without pre-filling an approval.

Download the blank message-ownership worksheet

Sources and limits

Repository source checked at commit 48039bb…4c80: the pinned README, application entry, mail routes, schema, attachment helper, tool paths, agent surface, and MCP surface. Cloudflare’s official Email Service, Durable Objects SQLite, R2, and Agents documentation supports only the attributed platform vocabulary.

The repository declares Apache-2.0; dependency, model, service, and generated-output terms were not audited. No reliability, exactly-once delivery, transactional storage, security, authorization sufficiency, recipient delivery, adoption, or personal-use result is claimed.

Back to field notes