Attachments API

Upload files and download attachments from messages.

POST /v1/attachments

POST/v1/attachments

Upload a file as multipart form data. Max file size: 25 MB. Requires full-access API key. Scoped (mailbox-restricted) keys cannot upload attachments.

curl
curl -X POST https://api.robotomail.com/v1/attachments \
  -H "Authorization: Bearer $ROBOTOMAIL_API_KEY" \
  -F "file=@report.pdf"
response — 201 Created
{
  "id": "a7b8c9d0-bcde-4f01-2345-777777777777",
  "filename": "report.pdf",
  "sizeBytes": 204800
}

Include the returned id in the attachments array when sending a message.

Errors

  • 400 — No file provided
  • 403 — Scoped API key (full access required)
  • 413 — File exceeds 25 MB or storage limit exceeded

GET /v1/attachments/:id

GET/v1/attachments/:id

Get attachment metadata and a presigned download URL (valid for 24 hours). Works for both outbound uploads and inbound message attachments — inbound attachments are owned by the recipient (the user who owns the receiving mailbox), so the same access check applies. Mailbox-scoped API keys can only access attachments linked to a message in an in-scope mailbox. Unattached uploads return 404 for scoped keys.

For inbound messages with inline images, this endpoint is the REST way to fetch a fresh presigned URL per attachment when rewriting cid: URLs in the HTML body. See Inbound attachments for the full inline image rewrite example.

response — 200 OK
{
  "id": "a7b8c9d0-bcde-4f01-2345-777777777777",
  "messageId": "b2c3d4e5-6789-4abc-def0-222222222222",
  "userId": "u1234",
  "filename": "report.pdf",
  "contentType": "application/pdf",
  "sizeBytes": 204800,
  "r2Key": "u1234/inbound/a7b8c9d0.../report.pdf",
  "contentId": null,
  "createdAt": "2026-04-09T12:00:00.000Z",
  "url": "https://r2.cloudflarestorage.com/...?signed-24h"
}
  • contentId — for inline images, the Content-ID header value (without angle brackets). Match this against cid:foo references in the HTML body. null for normal attachments and outbound uploads.
  • messageId — the parent Message row this attachment is linked to. null for orphaned uploads not yet attached to a sent message.
  • r2Key — internal storage key (returned for backwards compat — do not depend on its shape).
  • url — presigned R2 URL, valid for 24 hours from the moment of this request. To get a fresh URL after expiry, call this endpoint again.

Errors

  • 402INBOUND_LIMIT_EXCEEDED: the attachment is linked to an inbound message that was received while the account was over its monthly inbound cap. Outbound uploads and attachments on under-limit inbound messages are unaffected. See 402 INBOUND_LIMIT_EXCEEDED
  • 404 — Attachment not found, or (for scoped keys) not linked to an in-scope mailbox

DELETE /v1/attachments/:id

DELETE/v1/attachments/:id

Delete an attachment. Frees the storage from your account quota. Mailbox-scoped API keys can only delete attachments linked to a message in an in-scope mailbox.

response — 200 OK
{ "deleted": true }