Skip to content

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.

If the email API fails, the file stays in the outbox. The platform retries.

Every outgoing email is a file you can inspect. Nothing hidden.

The agent doesn’t need email credentials or API access. Just write a file.

The agent can’t access email APIs directly — it can only write files. This limits the blast radius of bugs.

Agent writes JSON → /data/outbox/email/
Platform reads outbox files
Sends via Resend API
Moves file to sent/ or failed/
/data/outbox/
├── email/ # Pending - agent writes here
├── sent/ # Successfully sent
└── failed/ # Failed to send (after retries)

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"
}
FieldTypeDescription
tostring[]Recipient email addresses
subjectstringEmail subject line
bodystringPlain text email body
statusstringAlways "pending" when written
FieldTypeDescription
ccstring[]CC recipients
in_reply_tostringMessage-ID of email being replied to
referencesstringSpace-separated Message-IDs for threading
attachmentsarrayFile attachments (see below)

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 to
  • references: Chain of Message-IDs in the thread

The platform passes these headers to Resend, which sets them correctly in the outgoing email.

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.

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

After the agent’s turn completes, the platform:

  1. Lists files in /data/outbox/email/
  2. Reads each JSON file
  3. Sends via Resend
  4. Moves to sent/ or failed/

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"
}

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"
}

You can view outbox contents by asking your agent:

“What files are in /data/outbox/“