Skip to main content

Documentation Index

Fetch the complete documentation index at: https://orbit-docs.devotel.io/llms.txt

Use this file to discover all available pages before exploring further.

Email attachments

Email sends through POST /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 — pre-uploaded to your file store or to Orbit’s /v1/files) 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.

Limits

ConstraintValue
Per-attachment size10 MB
Total per-email size25 MB (across all attachments combined)
Max attachments per email20

MIME allowlist

The content_type field must be one of:
application/pdf
application/msword
application/vnd.openxmlformats-officedocument.wordprocessingml.document  (.docx)
application/vnd.ms-excel
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet         (.xlsx)
application/vnd.ms-powerpoint
application/vnd.openxmlformats-officedocument.presentationml.presentation (.pptx)
text/csv
text/plain
application/zip
image/jpeg
image/png
image/gif
image/webp
image/svg+xml
Anything else is rejected with 422 VALIDATION_ERROR. We block executables and unknown types so a customer can’t accidentally hand their domain reputation to a malware payload.

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

ApproachWhen to use
urlFiles already hosted on your CDN, S3, or /v1/files. Preferred — keeps the request small and lets the platform stream the bytes server-side.
contentSmall files generated inline (signed PDFs, dynamic CSVs) where the round-trip to upload first isn’t worth it. Always base64-encoded.
Each attachment object MUST include either url or content — not both, not neither.

Send with curl

URL-based attachment

curl -X POST https://orbit-api.devotel.io/api/v1/messages/email \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "from": "billing@yourdomain.com",
    "subject": "Your invoice for May 2026",
    "html": "<p>Your invoice is attached.</p>",
    "attachments": [
      {
        "filename": "invoice-may-2026.pdf",
        "content_type": "application/pdf",
        "url": "https://files.yourdomain.com/invoices/may-2026.pdf",
        "size": 348112
      }
    ]
  }'

Inline base64 attachment

curl -X POST https://orbit-api.devotel.io/api/v1/messages/email \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "from": "billing@yourdomain.com",
    "subject": "Receipt",
    "html": "<p>Receipt attached.</p>",
    "attachments": [
      {
        "filename": "receipt.pdf",
        "content_type": "application/pdf",
        "content": "JVBERi0xLjQKJeLjz9MK..."
      }
    ]
  }'

Send with the Node.js SDK

import { Devotel } from "@devotel/orbit-sdk";
import { readFileSync } from "node:fs";

const orbit = new Devotel({ apiKey: process.env.ORBIT_API_KEY! });

await orbit.messages.send({
  channel: "email",
  to: "user@example.com",
  from: "billing@yourdomain.com",
  subject: "Your invoice for May 2026",
  html: "<p>Your invoice is attached.</p>",
  attachments: [
    {
      filename: "invoice-may-2026.pdf",
      content_type: "application/pdf",
      content: readFileSync("./invoice-may-2026.pdf").toString("base64"),
    },
  ],
});

Send with the Python SDK

import base64
from orbit import Orbit

orbit = Orbit(api_key="dv_live_sk_...")

with open("invoice-may-2026.pdf", "rb") as f:
    payload = base64.b64encode(f.read()).decode("ascii")

orbit.messages.send(
    channel="email",
    to="user@example.com",
    from_address="billing@yourdomain.com",
    subject="Your invoice for May 2026",
    html="<p>Your invoice is attached.</p>",
    attachments=[
        {
            "filename": "invoice-may-2026.pdf",
            "content_type": "application/pdf",
            "content": payload,
        }
    ],
)

Send with the Go SDK

package main

import (
    "encoding/base64"
    "os"

    orbit "github.com/devotel/orbit-go"
)

func main() {
    client := orbit.NewClient("dv_live_sk_...")

    pdf, _ := os.ReadFile("invoice-may-2026.pdf")
    b64 := base64.StdEncoding.EncodeToString(pdf)

    client.Messages.Send(orbit.SendMessageRequest{
        Channel: "email",
        To:      "user@example.com",
        From:    "billing@yourdomain.com",
        Subject: "Your invoice for May 2026",
        HTML:    "<p>Your invoice is attached.</p>",
        Attachments: []orbit.EmailAttachment{
            {
                Filename:    "invoice-may-2026.pdf",
                ContentType: "application/pdf",
                Content:     b64,
            },
        },
    })
}

Send with the Java SDK

import io.devotel.orbit.Orbit;
import io.devotel.orbit.models.EmailAttachment;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

Orbit orbit = new Orbit("dv_live_sk_...");

byte[] pdf = Files.readAllBytes(Path.of("invoice-may-2026.pdf"));
String b64 = Base64.getEncoder().encodeToString(pdf);

orbit.messages().sendEmail(
    "user@example.com",
    "billing@yourdomain.com",
    "Your invoice for May 2026",
    "<p>Your invoice is attached.</p>",
    new EmailAttachment("invoice-may-2026.pdf", "application/pdf", b64)
);

Send with the PHP SDK

<?php
use Devotel\Orbit\OrbitClient;

$orbit = new OrbitClient("dv_live_sk_...");

$pdf = file_get_contents("invoice-may-2026.pdf");
$b64 = base64_encode($pdf);

$orbit->messages->send([
    "channel" => "email",
    "to" => "user@example.com",
    "from" => "billing@yourdomain.com",
    "subject" => "Your invoice for May 2026",
    "html" => "<p>Your invoice is attached.</p>",
    "attachments" => [[
        "filename" => "invoice-may-2026.pdf",
        "content_type" => "application/pdf",
        "content" => $b64,
    ]],
]);

Send with the Ruby SDK

require "orbit"
require "base64"

orbit = Orbit::Client.new(api_key: "dv_live_sk_...")

pdf = File.binread("invoice-may-2026.pdf")
b64 = Base64.strict_encode64(pdf)

orbit.messages.send(
  channel: "email",
  to: "user@example.com",
  from: "billing@yourdomain.com",
  subject: "Your invoice for May 2026",
  html: "<p>Your invoice is attached.</p>",
  attachments: [
    {
      filename: "invoice-may-2026.pdf",
      content_type: "application/pdf",
      content: b64
    }
  ]
)

Send with the C# SDK

using Devotel.Orbit;

var client = new OrbitClient("dv_live_sk_...");

var pdf = File.ReadAllBytes("invoice-may-2026.pdf");
var b64 = Convert.ToBase64String(pdf);

await client.Messages.SendAsync(new SendEmailRequest
{
    To = "user@example.com",
    From = "billing@yourdomain.com",
    Subject = "Your invoice for May 2026",
    Html = "<p>Your invoice is attached.</p>",
    Attachments = new[]
    {
        new EmailAttachment
        {
            Filename    = "invoice-may-2026.pdf",
            ContentType = "application/pdf",
            Content     = b64,
        },
    },
});

Validation errors

CodeHTTPCause
VALIDATION_ERROR422Filename contains /, \\, or ..; MIME type not on the allowlist; total size exceeds 25 MB; more than 20 attachments; neither url nor content supplied.
EMAIL_ATTACHMENT_FETCH_FAILED422Orbit could not fetch a url-style attachment (timeout, 404, host outside the SSRF allowlist). Re-host the file or use the /v1/files upload endpoint.
EMAIL_ATTACHMENT_TOO_LARGE413The fetched bytes exceed the per-file 10 MB cap.

See also