Email attachments
Email sends throughPOST /api/v1/messages/email accept up to 20 attachments per email, totalling 25 MB across all attachments (RFC 5322 ceiling), with a per-file cap of 10 MB. Each attachment is referenced either by url (preferred — an Orbit-issued GCS-signed URL, e.g. the one returned by the Files API) or as inline base64 content.
URL-based attachments are fetched server-side, base64-encoded, and forwarded to the upstream provider. Orbit applies an SSRF allowlist so an attacker who controls a url field can’t pivot Orbit’s outbound network into your private network. The allowlist accepts only HTTPS URLs on Orbit’s storage host (storage.googleapis.com, or any *.storage.googleapis.com subdomain) — files hosted on your own CDN, S3 bucket, or any other host are rejected with 422 VALIDATION_ERROR (URL must point to our files service). To send a file you host yourself, upload it to the Files API first and reference the signed URL it returns (or inline it as base64 content).
Limits
MIME allowlist
Thecontent_type field must be one of:
422 VALIDATION_ERROR. We block executables and unknown types so a customer can’t accidentally hand their domain reputation to a malware payload.
image/svg+xml is intentionally NOT on the list — SVG files are XML and can embed <script> elements, event handlers, or <foreignObject> HTML. If we accepted SVG attachments, a forwarded SVG could turn into stored XSS the moment a downstream client rendered it inline.
Filename rules
- Required, max 255 chars.
- May not contain
/,\\, or..— guards against path traversal in downstream tools that re-emit the filename. - The filename surfaces verbatim in the recipient’s mail client.
URL vs content
Each attachment object MUST include either
url or content — not both, not neither.
Send with curl
URL-based attachment
Inline base64 attachment
Send with the Node.js SDK
SDK sample matrix
The Node.js and browser SDKs are GA today; first-party Python / Go / Java / PHP / Ruby / .NET SDKs are published to their registries or in final beta. Where a language’s typed scope does not yet exposesendEmail, the sample below goes through that language’s escape hatch — client.request / client.Request / $client->request / client.RequestAsync — which posts the exact same body as the curl samples above. Scope per language is on the SDK index.
- Node
- Python
- Go
- Ruby
- PHP
- Java
- C#
Idempotency-Key on every non-GET, so a retry cannot double-send.
Validation errors
See also
- Channels → Email — domain setup, tracking, suppression lists.
- Files API — pre-upload large attachments and reference them by URL.
- Messaging API — full
POST /api/v1/messages/emailschema.