> ## Documentation Index
> Fetch the complete documentation index at: https://agentteamemail.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Message archive layout in R2 object storage

> How AgentTeam Email structures inbound and outbound message bundles in R2, including file names, status values, and hosted-deployment prefixes.

AgentTeam Email writes every inbound and outbound message to Cloudflare R2 as a bundle of immutable artifacts in the supported self-hosted inbound path. R2 is the durable archive and completion marker store — it is not the live delivery queue, retry store, or operational database. Every object identity is a [UUIDv7](https://www.ietf.org/rfc/rfc9562.html) in canonical lowercase form, and all date path segments are UTC.

## Inbound bundle

Every message received by the Cloudflare Email Worker produces an inbound bundle at the following path:

```text theme={null}
orgs/<org_public_id>/domains/<recipient_domain>/mail/inbound/YYYY/MM/DD/<ingest_id>/
```

`ingest_id` is a UUIDv7 generated by the Cloudflare Worker at receive time. It is not derived from the message hash, mailbox, `Message-ID` header, or any Cloudflare routing data.

Inbound group forwarding fanout may also create target-side inbound
local-route bundles for Agent Mail mailboxes. Those bundles use
`schema: "agent-mail.inbound.local-route.edge.v1"` and link back to the source
inbound bundle. They are receive-side routing records, not Cloudflare Worker
commit markers and not new authored outbound sends.

### Inbound files

| File          | Description                                                                                                                                                                                                                    |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `raw.eml`     | Exact RFC 822 bytes as received by the Cloudflare Worker. The Worker never parses MIME, edits headers, rewrites the body, or injects provenance headers before writing this object.                                            |
| `edge.json`   | Envelope metadata, Worker-observed receive surface, and the durable inbound commit marker. Written after `raw.eml` succeeds. The reconciler discovers bundles by listing for keys ending in `/edge.json`.                      |
| `result.json` | Delivery result and final status. Written only after the bundle reaches a terminal state (delivered, DSN submitted, or DSN suppressed). Its presence is the idempotency marker — a bundle without `result.json` is incomplete. |
| `dsn.eml`     | Agent Mail–generated Delivery Status Notification. Present only when the status is `delivery_failed_dsn_submitted`. Not written for delivered mail or suppressed DSNs.                                                         |

### Inbound status values

`result.json` carries one of three terminal statuses:

| Status                           | Meaning                                                                                                                                                          |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `delivered`                      | The message was successfully delivered to the recipient's WildDuck mailbox.                                                                                      |
| `delivery_failed_dsn_submitted`  | Delivery failed permanently (no local mailbox). A DSN was generated, written as `dsn.eml`, and submitted to the outbound relay with a null SMTP envelope sender. |
| `delivery_failed_dsn_suppressed` | Delivery failed permanently but the original envelope sender was null or invalid, so no DSN was sent.                                                            |

<Note>
  If a processing attempt fails transiently, `result.json` is not written and the bundle remains incomplete.
  The reconciler retries incomplete bundles up to three attempts before marking the Mongo queue item as
  `blocked` for operator review. Blocked items are not terminal archive state.
</Note>

## Outbound bundle

Every message relayed for outbound delivery produces a bundle at the following path:

```text theme={null}
mail/outbound/<source_domain>/YYYY/MM/DD/<send_id>/
```

`send_id` is a UUIDv7 generated by the internal SMTP relay at relay time. It is not the ZoneMTA queue ID.

### Outbound files

| File                              | Description                                                                                                                                                                     |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `relay.eml`                       | Exact SMTP DATA bytes accepted from ZoneMTA, preserving the internal `X-Agent-Mail-ZoneMTA-Queue-ID` header.                                                                    |
| `relay.json`                      | Internal SMTP relay boundary metadata: `send_id`, route type, delivery boundary, envelope addresses, and relay timestamp.                                                       |
| `provider.eml` or `provider.json` | Provider-bound delivery payload for SES or Cloudflare Email Sending. Ordinary authored sends always produce provider-bound payloads once the relay builds the provider request. |
| `result.json`                     | Terminal outbound result and completion marker for the bundle.                                                                                                                  |

Inbound group forwarding fanout may create source-side local-route relay
boundary bundles. Those bundles do not include `provider.eml` or
`provider.json`; they are fanout routing records, not authored outbound sends.

### Outbound status values

Ordinary authored sends are provider-bound even when every recipient is on an
AgentTeam Email domain.

Provider-bound `result.json` carries one of three terminal statuses:

| Status              | Meaning                                                                     |
| ------------------- | --------------------------------------------------------------------------- |
| `provider_accepted` | The external delivery boundary accepted the message for delivery.           |
| `provider_rejected` | The external delivery boundary rejected the message with a permanent error. |
| `provider_failed`   | The external delivery boundary returned a transient or unexpected failure.  |

Inbound group forwarding fanout local-route bundles carry one of two terminal
statuses:

| Status               | Meaning                                                                  |
| -------------------- | ------------------------------------------------------------------------ |
| `local_routed`       | The receive-side fanout copy was delivered locally and archived.         |
| `local_route_failed` | The receive-side fanout copy could not be locally delivered or archived. |

<Note>
  ZoneMTA owns outbound retry and bounce behavior. When ZoneMTA retries by resubmitting to the internal SMTP
  relay, the relay generates a new `send_id` and a new outbound bundle. The shared `zonemta_queue_id` field in
  `relay.json` links those bundles to the same ZoneMTA queue entry.
</Note>

## Hosted deployments

In AgentTeam Email hosted deployments, all archive objects are scoped per organization:

* Every object is prefixed with `orgs/<org_public_id>/` so bundles from different organizations never share a path namespace.
* Archive objects are not publicly served.
* Customer Workers receive short-lived R2 temporary credentials scoped to their organization prefix for archive writes. Parent R2 credentials remain backend-owned and are not exposed to customer Workers, browsers, public APIs, or user-facing diagnostics.
