The Outbox Pattern
Your agent doesn’t send emails directly. Instead, it writes files to an outbox directory, and the platform picks them up and sends them.
Why an outbox?
Section titled “Why an outbox?”Reliability
Section titled “Reliability”If the email API fails, the file stays in the outbox. The platform retries.
Auditability
Section titled “Auditability”Every outgoing email is a file you can inspect. Nothing hidden.
Simplicity
Section titled “Simplicity”The agent doesn’t need email credentials or API access. Just write a file.
Isolation
Section titled “Isolation”The agent can’t access email APIs directly — it can only write files. This limits the blast radius of bugs.
How it works
Section titled “How it works”Agent writes JSON → /data/outbox/email/ ↓ Platform reads outbox files ↓ Sends via Resend API ↓ Moves file to sent/ or failed/Directory structure
Section titled “Directory structure”/data/outbox/├── email/ # Pending - agent writes here├── sent/ # Successfully sent└── failed/ # Failed to send (after retries)File format
Section titled “File format”Agent writes JSON files to /data/outbox/email/:
{ "to": ["recipient@example.com"], "subject": "Re: Your question", "body": "Here's what I found...", "in_reply_to": "<original-message-id@example.com>", "references": "<msg1@example.com> <msg2@example.com>", "status": "pending"}Required fields
Section titled “Required fields”| Field | Type | Description |
|---|---|---|
to | string[] | Recipient email addresses |
subject | string | Email subject line |
body | string | Plain text email body |
status | string | Always "pending" when written |
Optional fields
Section titled “Optional fields”| Field | Type | Description |
|---|---|---|
cc | string[] | CC recipients |
in_reply_to | string | Message-ID of email being replied to |
references | string | Space-separated Message-IDs for threading |
attachments | array | File attachments (see below) |
Threading
Section titled “Threading”For proper email threading, include:
{ "in_reply_to": "<CAG+abc123@mail.gmail.com>", "references": "<CAG+first@mail.gmail.com> <CAG+abc123@mail.gmail.com>"}in_reply_to: The Message-ID of the email you’re replying toreferences: Chain of Message-IDs in the thread
The platform passes these headers to Resend, which sets them correctly in the outgoing email.
Attachments
Section titled “Attachments”Include files as base64-encoded attachments:
{ "to": ["recipient@example.com"], "subject": "Report attached", "body": "Please find the report attached.", "attachments": [ { "filename": "report.pdf", "content": "JVBERi0xLjQK..." } ]}The agent typically generates files in /data/ first, then base64-encodes them for the outbox.
File naming
Section titled “File naming”Files in /data/outbox/email/ should have unique names. Common patterns:
{timestamp}.json— e.g.,1704379200000.json{timestamp}-reply.json— e.g.,1704379200000-reply.json
Processing
Section titled “Processing”After the agent’s turn completes, the platform:
- Lists files in
/data/outbox/email/ - Reads each JSON file
- Sends via Resend
- Moves to
sent/orfailed/
Sent and failed directories
Section titled “Sent and failed directories”Successfully sent emails are moved here with metadata added:
{ "to": ["recipient@example.com"], "subject": "Re: Question", "body": "...", "status": "sent", "sent_at": "2026-01-04T12:00:00Z", "resend_id": "abc123"}failed/
Section titled “failed/”Emails that failed after retries:
{ "to": ["recipient@example.com"], "subject": "Re: Question", "body": "...", "status": "failed", "error": "Invalid recipient address", "failed_at": "2026-01-04T12:00:00Z"}Manual inspection
Section titled “Manual inspection”You can view outbox contents by asking your agent:
“What files are in /data/outbox/“
Next steps
Section titled “Next steps”- Email JSON Reference — Complete field reference
- Architecture — How the platform works