Robotomail — Give Your AI Agent a Real Inbox
Robotomail lets an AI agent send, receive, and react to email programmatically. It is API-first email infrastructure for autonomous agents, assistants, and workflows.
Use Robotomail when you want an agent to:
- - send outbound email, reminders, updates, or follow-ups
- read inbound email from a real inbox
- react to incoming email via webhooks or real-time SSE events
- reply in existing threads using normal email semantics
- use a hosted
robotomail.co address or a custom domain
Best-fit use cases
1. Agent support inbox
Give your agent a real inbox so it can classify, summarize, draft, or reply to incoming support emails.
2. Outbound follow-ups and reminders
Let an agent send reminders, nudges, receipts, booking confirmations, or outbound follow-ups from its own mailbox.
3. Real-time email triggers
Subscribe to inbound email events with webhooks or SSE so your agent can wake up and act immediately.
Fast start
If the user is new to Robotomail, the fastest path is:
- 1. Sign up at
https://robotomail.com or create an account via INLINECODE2 - Create or list a mailbox with
GET /v1/mailboxes or INLINECODE4 - Send a test email with INLINECODE5
- Read inbound email with INLINECODE6
- Subscribe to inbound events via webhook or SSE
Authentication
All requests require an API key in the Authorization header:
CODEBLOCK0
Base URL: INLINECODE8
If the user doesn't have an API key yet, they can sign up at https://robotomail.com or you can create an account via POST /v1/signup.
Quick Reference — What Can I Do?
| Task | Method | Endpoint |
|---|
| Send an email | POST | INLINECODE10 |
| List inbox messages |
GET |
/v1/mailboxes/{id}/messages?direction=INBOUND |
| Read a specific message | GET |
/v1/mailboxes/{id}/messages/{msgId} |
| List conversation threads | GET |
/v1/mailboxes/{id}/threads |
| Read a thread | GET |
/v1/mailboxes/{id}/threads/{tid} |
| List mailboxes | GET |
/v1/mailboxes |
| Create a mailbox | POST |
/v1/mailboxes |
| Add a custom domain | POST |
/v1/domains |
| Verify domain DNS | POST |
/v1/domains/{id}/verify |
| Set up a webhook | POST |
/v1/webhooks |
| Stream events with SSE | GET |
/v1/events |
| Upload an attachment | POST |
/v1/attachments (multipart) |
| Download an attachment | GET |
/v1/attachments/{id} |
| Check account & usage | GET |
/v1/account |
For full endpoint details including request/response schemas, read references/api-reference.md.
Webhooks vs SSE
Use webhooks when Robotomail should push events to your public HTTPS endpoint.
Use SSE when the agent wants a live event stream over a single long-lived connection, for example when running a local listener or agent loop.
If the user says things like "stream inbound mail", "listen for new messages", or "real-time inbox events", prefer SSE.
Decision Tree — Common Tasks
"Send an email"
- 1. List mailboxes:
GET /v1/mailboxes — find the mailbox to send from - Send:
POST /v1/mailboxes/{id}/messages with to, subject, bodyText (and optionally bodyHtml) - To reply to an existing message, include
inReplyTo with the original message's messageId header value
"Check my inbox" / "Read my email"
- 1. List mailboxes: INLINECODE33
- Fetch inbound messages: INLINECODE34
- Read a specific message: INLINECODE35
"Reply to an email"
- 1. Read the original message to get its
messageId field - Send reply:
POST /v1/mailboxes/{id}/messages with inReplyTo set to the original's messageId value - Threading is automatic — the reply joins the same thread
"Set up email for a new domain"
- 1. Add domain:
POST /v1/domains with INLINECODE41 - Read the
dnsRecords from the response — tell the user to configure these at their DNS provider - After DNS is configured, verify: INLINECODE43
- Once verified, create a mailbox:
POST /v1/mailboxes with INLINECODE45
"Set up a webhook for incoming email"
- 1. Create webhook:
POST /v1/webhooks with url and INLINECODE48 - Save the
secret from the response, it is shown only once - Verify deliveries with
X-Robotomail-Signature header (HMAC-SHA256 of payload using secret)
See references/webhook-verification.md for signature verification code.
"Listen for incoming email in real time" / "Use SSE"
- 1. Connect to INLINECODE52
- Filter or react to
message.received, message.delivered, message.bounced, and INLINECODE56 - Use SSE when the agent wants a live stream instead of public webhook delivery
"Send an email with an attachment"
- 1. Upload the file:
POST /v1/attachments (multipart/form-data, field name file, max 25MB) - Note the returned attachment INLINECODE59
- Send the message with INLINECODE60
"Read an inbound email's attachments" / "Handle inline images"
Inbound messages with attachments expose them on two surfaces with different shapes. Pick the right one for your access pattern — do not assume REST responses contain ready-to-use download URLs.
- 1. Webhook / SSE
message.received payload — data.attachments[] is delivered with a ready-to-use download_url field (presigned R2 URL, valid 24h from publish time) on each attachment, alongside id, filename, content_type, size_bytes, and content_id. Field names are snake_case. Fetch each file directly — no Authorization header needed:
for att in event.data.attachments:
bytes = HTTP_GET(att.download_url)
save_to(att.filename, bytes)
- 2. REST
GET /v1/mailboxes/{id}/messages and GET /v1/mailboxes/{id}/messages/{msgId} — attachments[] contains metadata only (id, filename, contentType, sizeBytes, contentId), no URL field. To download, call GET /v1/attachments/{id} for each attachment id and use the url field on that response. Field names are camelCase. This is also how you refresh an expired download_url from an old webhook/SSE replay.
Inline images: when an attachment's content_id (snake_case in webhook/SSE) or contentId (camelCase in REST) is non-null, the attachment is referenced in body_html / bodyHtml as <img src="cid:<content_id>">. Rewrite each cid: reference to a real downloadable URL before passing the HTML to a renderer or vision model. From a webhook/SSE payload (where download_url is already on the attachment):
for att in event.data.attachments where att.content_id is not None:
body_html = body_html.replace(f"cid:{att.content_id}", att.download_url)
From a REST message read, fetch a presigned URL per inline attachment first:
CODEBLOCK3
Drop limits: if a message has more than 20 attachments, or any single attachment exceeds 25 MB, the payload includes attachments_dropped: true and attachments_dropped_reason: "size" | "count" | "both". The message itself is still delivered, but the over-limit attachments are not stored. Tell the user if you see this flag.
Key Constraints
- - Daily send limits: 100/day (free), 500–2,000/day (paid, varies by tier) per mailbox — resets at midnight UTC
- Monthly send limits: 5,000/month (free), 15,000/month (Developer), unlimited (Growth, Scale) per mailbox
- Velocity limits: 30 messages/min per mailbox, 60 messages/min per account — returns
429 if exceeded - Bounce rate: Must stay below 3% over a 7-day rolling window (minimum 50 messages). Exceeding this auto-suspends the mailbox.
- Complaint rate: Must stay below 0.05% over a 7-day rolling window (minimum 50 messages). Exceeding this auto-suspends the mailbox.
- Attachment size: Max 25MB per file
- Storage: 1GB (free), 10GB (Developer), 25GB (Growth), 100GB (Scale)
- Free tier: 3 mailboxes on
robotomail.co only - Paid plans start at $19/mo (Developer): 10+ mailboxes, custom domains
If a send returns 429, the mailbox has hit its daily/monthly limit or velocity limit. Tell the user and suggest slowing down or upgrading if on the free plan.
Error Handling
All errors return {"error": "message"} with standard HTTP status codes:
- -
401 — Missing or invalid API key - INLINECODE94 — Account suspended or scoped key accessing a restricted resource. When suspended, response includes
{ "suspended": true, "reason": "bounce_rate_exceeded" }. Tell the user to contact support@robotomail.com. - INLINECODE96 — Resource not found
- INLINECODE97 — Rate limit, velocity limit, or send quota exceeded
- INLINECODE98 — Attachment too large
Tips
- - Always use
bodyText for the plain-text version. Add bodyHtml only when rich formatting is needed. - Use threads (
GET /v1/mailboxes/{id}/threads/{tid}) to see full conversation history before replying. - When listing messages, use
since parameter (ISO-8601) to fetch only recent messages. - Suppression list (
GET /v1/suppressions) contains bounced/complained addresses — check before sending to addresses that previously failed.
Robotomail — 为你的AI智能体配备真实收件箱
Robotomail让AI智能体能够以编程方式发送、接收和回复邮件。它是面向自主智能体、助手和工作流的API优先邮件基础设施。
当你希望智能体能够执行以下操作时,请使用Robotomail:
- - 发送外发邮件、提醒、更新或跟进邮件
- 从真实收件箱读取入站邮件
- 通过webhook或实时SSE事件响应入站邮件
- 使用标准邮件语义在现有邮件线程中回复
- 使用托管的robotomail.co地址或自定义域名
最佳适用场景
1. 智能体支持收件箱
为你的智能体配备真实收件箱,使其能够分类、总结、草拟或回复收到的支持邮件。
2. 外发跟进与提醒
让智能体从其自有邮箱发送提醒、催促通知、收据、预订确认或外发跟进邮件。
3. 实时邮件触发器
通过webhook或SSE订阅入站邮件事件,使智能体能够立即唤醒并采取行动。
快速入门
如果用户是Robotomail新手,最快路径如下:
- 1. 在https://robotomail.com注册,或通过POST /v1/signup创建账户
- 使用GET /v1/mailboxes或POST /v1/mailboxes创建或列出邮箱
- 使用POST /v1/mailboxes/{id}/messages发送测试邮件
- 使用GET /v1/mailboxes/{id}/messages?direction=INBOUND读取入站邮件
- 通过webhook或SSE订阅入站事件
身份认证
所有请求都需要在Authorization头中包含API密钥:
Authorization: Bearer APIKEY>
基础URL: https://api.robotomail.com
如果用户还没有API密钥,可以在https://robotomail.com注册,或者通过POST /v1/signup创建账户。
快速参考 — 我能做什么?
| 任务 | 方法 | 端点 |
|---|
| 发送邮件 | POST | /v1/mailboxes/{id}/messages |
| 列出收件箱消息 |
GET | /v1/mailboxes/{id}/messages?direction=INBOUND |
| 读取特定消息 | GET | /v1/mailboxes/{id}/messages/{msgId} |
| 列出会话线程 | GET | /v1/mailboxes/{id}/threads |
| 读取线程 | GET | /v1/mailboxes/{id}/threads/{tid} |
| 列出邮箱 | GET | /v1/mailboxes |
| 创建邮箱 | POST | /v1/mailboxes |
| 添加自定义域名 | POST | /v1/domains |
| 验证域名DNS | POST | /v1/domains/{id}/verify |
| 设置webhook | POST | /v1/webhooks |
| 使用SSE流式传输事件 | GET | /v1/events |
| 上传附件 | POST | /v1/attachments(multipart) |
| 下载附件 | GET | /v1/attachments/{id} |
| 查看账户及使用情况 | GET | /v1/account |
完整端点详情(包括请求/响应模式)请参阅references/api-reference.md。
Webhook与SSE对比
当Robotomail需要将事件推送到你的公共HTTPS端点时,请使用webhook。
当智能体希望通过单个长连接获取实时事件流时(例如运行本地监听器或智能体循环),请使用SSE。
如果用户提到流式传输入站邮件、监听新消息或实时收件箱事件,优先推荐SSE。
决策树 — 常见任务
发送邮件
- 1. 列出邮箱:GET /v1/mailboxes — 找到要发送邮件的邮箱
- 发送:POST /v1/mailboxes/{id}/messages,包含to、subject、bodyText(可选bodyHtml)
- 要回复现有消息,请在inReplyTo中包含原始消息的messageId头值
查看我的收件箱 / 读取我的邮件
- 1. 列出邮箱:GET /v1/mailboxes
- 获取入站消息:GET /v1/mailboxes/{id}/messages?direction=INBOUND
- 读取特定消息:GET /v1/mailboxes/{id}/messages/{msgId}
回复邮件
- 1. 读取原始消息以获取其messageId字段
- 发送回复:POST /v1/mailboxes/{id}/messages,将inReplyTo设置为原始消息的messageId值
- 线程自动处理 — 回复将加入同一线程
为新域名设置邮件
- 1. 添加域名:POST /v1/domains,包含{domain: example.com}
- 从响应中读取dnsRecords — 告知用户在其DNS提供商处配置这些记录
- DNS配置完成后,进行验证:POST /v1/domains/{id}/verify
- 验证通过后,创建邮箱:POST /v1/mailboxes,包含{address: agent, domainId: }
为入站邮件设置webhook
- 1. 创建webhook:POST /v1/webhooks,包含url和events: [message.received]
- 保存响应中的secret,该值仅显示一次
- 使用X-Robotomail-Signature头验证投递(使用secret对payload进行HMAC-SHA256签名)
签名验证代码请参阅references/webhook-verification.md。
实时监听入站邮件 / 使用SSE
- 1. 连接到GET /v1/events
- 过滤或响应message.received、message.delivered、message.bounced和message.complaint事件
- 当智能体需要实时流而非公共webhook投递时,使用SSE
发送带附件的邮件
- 1. 上传文件:POST /v1/attachments(multipart/form-data,字段名file,最大25MB)
- 记录返回的附件id
- 使用attachments: []发送消息
读取入站邮件的附件 / 处理内嵌图片
带附件的入站消息在两个接口上以不同格式展示附件。请根据你的访问模式选择正确的接口 — 不要假设REST响应包含可直接使用的下载URL。
- 1. Webhook / SSE message.received payload — data.attachments[]中每个附件都包含可直接使用的downloadurl字段(预签名R2 URL,自发布起24小时有效),以及id、filename、contenttype、sizebytes和contentid。字段名为snake_case格式。直接获取每个文件 — 无需Authorization头:
for att in event.data.attachments:
bytes = HTTPGET(att.downloadurl)
save_to(att.filename, bytes)
- 2. REST GET /v1/mailboxes/{id}/messages和GET /v1/mailboxes/{id}/messages/{msgId} — attachments[]仅包含元数据(id、filename、contentType、sizeBytes、contentId),无URL字段。如需下载,对每个附件id调用GET /v1/attachments/{id},并使用该响应中的url字段。字段名为camelCase格式。这也是刷新旧webhook/SSE重放中过期download_url的方法。
内嵌图片: 当附件的contentid(webhook/SSE中为snakecase)或contentId(REST中为camelCase)非空时,该附件在bodyhtml/bodyHtml中被引用为
id>>。在将HTML传递给渲染器或视觉模型之前,将每个cid:引用重写为真实的可下载URL。来自webhook/SSE payload(附件已包含download_url):
for att in event.data.attachments where att.content_id is not None:
bodyhtml = bodyhtml.replace(fcid:{att.contentid}, att.downloadurl)
来自REST消息读取,先为每个内嵌附件获取预签名URL:
for att in message.attachments where att.contentId is not None:
url = GET(f/v1/attachments/{att.id}).url
bodyHtml = bodyHtml.replace(fcid:{att.contentId}, url)
丢弃