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/ ↓ Queue worker 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/:
{ "subject": "Re: Your question", "body": "Here's what I found...", "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: 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:
{ "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{uuid}.json— e.g.,a1b2c3d4-e5f6-7890-abcd-ef1234567890.json
The agent typically uses timestamps.
Processing
Section titled “Processing”After the agent exits, the queue worker:
- Lists files in
/data/outbox/email/ - Reads each JSON file
- Adds session footer to body
- 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:
{ "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:
{ "subject": "Re: Question", "body": "...", "status": "failed", "error": "Invalid recipient address", "failed_at": "2026-01-04T12:00:00Z"}Session footer
Section titled “Session footer”The platform automatically appends a session footer to every outgoing email:
---[buddy:a1b2 | ↑38 ↓5.0k R663k W37k $0.687 18.7%/200k | claude-haiku-4-5]This is added during processing — the agent doesn’t need to include it.
Manual inspection
Section titled “Manual inspection”You can view outbox contents:
- Ask your agent: “What files are in /data/outbox/”
- Check the dashboard file browser (coming soon)
- Export your R2 data
Next steps
Section titled “Next steps”- Email JSON Reference — Complete field reference
- Architecture — How the platform works