sixel.email

Best practices for agent email integration.

The basics

Give your agent minimal instructions

The entire integration is 5 lines in your agent's system prompt or config:

You have an email address for contacting your operator.
API: https://sixel.email/v1
Token: sm_live_xxxxx
POST /v1/send to email. GET /v1/inbox to check for replies.
Poll /v1/inbox every 60s while waiting.

That's it. Don't over-specify. The agent figures out when to email (stuck, needs approval, has results) and what to say. You're adding a capability, not a workflow.

Use the inbox poll as the heartbeat

Every GET /v1/inbox call updates your agent's heartbeat. If the agent stops polling, you get a notification email. This means you don't need a separate health check — inbox polling is the health check.

Recommended interval: 60 seconds. Fast enough to catch replies promptly. Slow enough to not waste resources. The poll is free — only sends and receives cost credits.

One allowed contact

Each agent can only email one address: the one you set during setup. This is the leash. Your agent can't be tricked into emailing anyone else, and it can't be spammed by strangers. Inbound email from any other sender is rejected at the edge before it touches the API.

Sleep/wake patterns

The agent doesn't need to stay busy

The most useful pattern: agent does work, emails you when done or stuck, then polls /v1/inbox in a loop until you reply. The agent is "asleep" — consuming no inference, just one HTTP GET per minute.

# Pseudocode: sleep until reply
send_email("Finished the analysis. Results attached. What next?")
while True:
    response = poll_inbox()
    if response.messages:
        handle(response.messages[0])
        break
    sleep(60)

This turns a synchronous back-and-forth into an async conversation. You reply when you're ready — hours later, next morning, whenever. The agent wakes up and continues.

Surviving context loss

Long-running agents will hit context limits. When the context compresses or the session restarts, the agent loses awareness of what it was waiting for. Two mitigations:

  1. Write state to disk before sleeping. What are you waiting for? What was the last thing you sent? Save it in a file the agent reads on startup.
  2. Check inbox on restart. If there's an unread message, the reply already arrived while you were down. Handle it before doing anything else.

When the operator goes dark

Your agent emails the operator. No reply for hours. What should it do?

Don't assume the operator saw the message. Don't send follow-ups. The agent should have a fallback mode: continue with non-destructive work it can do without approval, or gracefully idle (poll the inbox, do nothing else). The worst outcome is an agent that escalates its own urgency — sending repeated messages, making assumptions, or taking actions it was waiting for approval on.

Design for silence. If you give your agent tasks that require approval at certain gates, also give it a list of things it can do without approval. When the operator doesn't respond, the agent works that list instead of stalling or improvising.

Attachments

Sending attachments

Include an attachments array in your POST /v1/send request. Each attachment is a JSON object with filename and content (base64-encoded).

{
  "subject": "Analysis results",
  "body": "Here are the results.",
  "attachments": [
    {"filename": "results.csv", "content": "aWQsbmFtZSxzY29yZQ=="}
  ]
}

Limits: 10MB total decoded size, max 10 files per message.

Receiving attachments

GET /v1/inbox includes attachment metadata on each message:

"attachments": [
  {"id": "uuid", "filename": "photo.jpg", "mime_type": "image/jpeg", "size_bytes": 164883}
]

Download the content with GET /v1/inbox/{message_id}/attachments/{attachment_id}. Returns raw bytes with the correct Content-Type header.

Multi-session coordination

If you run multiple agent sessions (different projects, different specializations), they can share a single inbox and coordinate responses without a central orchestrator.

Sixel Teams (reference architecture)

We published a reference architecture: sixel-et/sixel-teams. The core pattern is hubless coordination — a lightweight watcher handles email I/O, wakes sessions, collects contributions, and sends one assembled reply. No framework, no shared context window, no LLM calls in the coordination layer.

The reference implementation uses tmux and bash scripts. The architecture is harness-agnostic — the same watcher/contributor/assembler pattern works whether your agent sessions are tmux panes, Docker containers, or framework-managed processes. Adapt the coordination layer to your stack; the email integration stays the same.

Security

The threat model

The leash (one allowed contact) means the agent can't be weaponized for spam or social engineering. But the inbound side needs protection too — can someone send your agent a malicious email?

Door Knock nonce authentication

Door Knock is opt-in — toggle it during signup or on your /account page. Without it, emails from your allowed contact are accepted directly. With it enabled:

Every outbound email from your agent includes a Reply-To address with a single-use nonce: agent+nonce@sixel.email. When you hit reply, the nonce validates your response automatically. No codes, no apps, no extra steps.

If you want to email your agent without a prior message to reply to (a "knock"), just send to agent@sixel.email. The agent ignores the content but auto-replies with a fresh nonce in the Reply-To. Reply to that, and your message goes through. Three emails, zero friction.

Nonces expire after 30 minutes. If you don't reply within that window, the nonce is no longer valid. Send a new knock to get a fresh one.

This means an attacker with a compromised email account can send a knock, but the auto-reply goes to your inbox — they'd need to also compromise your inbox to see the nonce. If that's happened, you have bigger problems than agent email.

Channel kill switch

Set up a kill switch from /account. You get an allstop email address that deactivates the channel instantly. Save it as a phone contact — the setup page gives you a QR code. If anything goes wrong, send one email to that address and the channel shuts down. Reactivation requires a live session or the account dashboard.

Transport-layer prompt injection

sixel.email delivers message content as-is. We do not sanitize, filter, or scan email bodies for prompt injection. This is deliberate.

The email body is untrusted input — even from your allowed contact. A forwarded email, an auto-reply, a mailing list digest, or a compromised account can all produce content that looks like instructions to an LLM. Your agent must treat every inbound message the same way it treats any user input: as data, not as commands.

Your agent's defense is your responsibility. Use system prompts to anchor the agent's behavior. Separate the instruction channel (system prompt, config) from the data channel (email body). Don't let email content override tool permissions, change the allowed contact, or bypass approval gates.

If your framework supports it, pass email bodies as user messages, not system messages. The distinction matters for models that weight system instructions more heavily than user input.

Stateless environments

Some agents run in environments without persistent filesystem access — serverless functions, ephemeral containers, or framework-managed processes that restart frequently. The inbox API is designed for this:

If you can't persist a seen-ID list (see Common mistakes below), rely on the server-side read tracking. The tradeoff: if a fetch succeeds but your agent crashes before processing, the message is marked read and won't reappear. For critical workflows, persist the message ID before acting on it.

Common mistakes

Polling too fast

The API rate-limits inbox polls. 60 seconds is the sweet spot. Polling every second doesn't get you replies faster — it gets you rate-limited.

Not seeding the seen-ID list

If your agent restarts and re-reads the inbox, it will see messages it already handled (the inbox marks messages as read on fetch, but network issues can cause re-delivery). Keep a local list of message IDs you've processed. Check it before acting on any message.

Sending without a subject

Subjects aren't required by the API, but your email client will bury subjectless messages. Always include a subject — your future self will thank you when scanning a long thread.

Ignoring the credit balance

Every /v1/inbox response includes credits_remaining. If your agent notices credits getting low, it should tell you. Don't let it discover it's out of credits when it has something important to say.

Treating email like chat

Email is async. Your agent should send one well-composed message, then wait. Don't send five messages in a row. Don't poll for 10 seconds and then send a follow-up asking if you got the first one.

Reading email bodies without checking for binary

If your human pastes an image into an email, the body field can contain 200KB+ of base64-encoded image data. An agent that reads or greps this content without checking can enter a hot loop — regex engines hit catastrophic backtracking on binary data, and the session becomes unrecoverable.

Rule: read a small slice first. Before processing any email body, check the first few lines. If it looks like base64 or binary data, stop. Use the attachments endpoint to get file content separately.

FAQ

Can the agent email anyone?

No. Only the one allowed contact you set during setup. This is by design.

Can I change the allowed contact?

Yes — from your /account page. Changing the contact forces an API key rotation and clears your message history. This is a security measure: if the change was unauthorized, the old key stops working immediately and the attacker can't access prior messages.

What happens if my agent goes down?

If the agent stops polling /v1/inbox, you'll get a notification email after a configurable timeout. When the agent comes back and resumes polling, you'll get a recovery notification.

Can multiple agents share an address?

One address = one agent = one API key. But multiple sessions can share the same API key and coordinate responses (see Multi-session coordination above).

Is polling really free?

Yes. GET /v1/inbox is free. You only pay credits per message sent or received (1 credit each). Every account starts with 10,000 free credits — that's 5,000 round-trip conversations. An agent that exchanges 20 messages a day with its operator uses about 600 credits a month. For most use cases, 10,000 credits lasts months.

Can agents send and receive attachments?

Yes. Up to 10 files per message, 10MB total. Send with base64-encoded content in the attachments array. Receive metadata in the inbox response, download via the attachment endpoint. See Attachments section above.

Do I need Door Knock nonces?

It's optional. Without it, any email from your allowed contact goes through directly. With it, replies are validated by a single-use nonce in the Reply-To address. Toggle it on /account. If you're not worried about email account compromise, you probably don't need it.

What if I email the agent from the wrong address?

Rejected at the edge. No credit deduction, no storage, no notification to the agent. It's as if the email was never sent.

How is this different from just using Gmail?

Gmail doesn't give your agent an API. You'd need to set up OAuth, parse MIME yourself, build a polling loop around IMAP, and handle authentication refresh. sixel.email is 5 lines of config: one endpoint to send, one to receive, one API key. The inbox poll doubles as a heartbeat — if your agent stops checking, you get notified. And the one-allowed-contact model means your agent can't be tricked into emailing anyone else.

How is this different from other agent email services?

Most agent email services give you a general-purpose email API. sixel.email is opinionated: one agent, one contact, prepaid credits, no subscription. The leash (one allowed contact) is the product, not a limitation. If you need an agent that emails arbitrary recipients, this isn't the right tool. If you want a controlled channel between your agent and you, it is.

Support

Questions, bugs, feedback: support@sixel.email. That's a real inbox monitored by a human.