Email

Send, track, and manage transactional emails via SMTP.

Requires an SMTP account configured in the dashboard. Supports HTML/text content, attachments (multipart), batch sending with variable substitution, scheduling, and tracking.

Endpoints

MethodPathPermission
POST
email.send
POST
email.send
POST
email.send
GET
email.history
GET
email.history
DELETE
email.send

Send Email

POST /api/v1/emails/send

Request

Response

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "to": "user@example.com",
    "subject": "Welcome!"
  }
}
json

Metadata & tracking options

Optional on /emails/send, /emails/send/multipart and /emails/batch

  • metadata — a flat object of strings, numbers or booleans (max 20 keys, 8 KB), returned unchanged in every email.* webhook. Lets you join events to your own records without storing Sendy ids.
  • track_opens — default true. Set to false to skip the open-tracking pixel.
  • track_clicks — default true. Set to false to leave links untouched, so a payment link does not depend on Sendy being reachable.
{
  "to": "customer@example.com",
  "subject": "Invoice INV-2026-0042",
  "html": "<p>Your invoice is ready.</p>",
  "metadata": { "invoice_id": "INV-2026-0042", "reminder": 1 },
  "track_clicks": false
}
json

In multipart requests these arrive as text fields: metadata as a JSON string, the two flags as "true" or "false".

Send with Attachments

POST /api/v1/emails/send/multipart • POST /api/v1/emails/send

Two ways to attach files to an email — pick the one that fits your client:

  • multipart/form-data (/emails/send/multipart): native file upload, up to 50 MB per file, max 10 files per request. Recommended for large files.
  • JSON with base64 (/emails/send): inline base64-encoded content. Total body capped at ~1 MB by default (≈ 750 KB of raw file after base64 expansion). Recommended for small files where you don't want to deal with multipart.

Both methods produce the same Email record with attachments[] populated. The file part field name in multipart can be anything (attachments, file, files[], etc.) — the API picks up every file part regardless of name.

multipart/form-data

JSON with base64

Response (both methods)

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "scheduled_at": null
  }
}
json

Fetch the email via GET /api/v1/emails/:id to inspect the stored attachments[] (each with id, filename, contentType, sizeBytes). The worker reads each file from disk and attaches it to the outgoing SMTP message automatically.

Batch Send

POST /api/v1/emails/batch

Request

Response

{
  "success": true,
  "data": [
    { "id": "uuid-1", "to": "alice@example.com", "status": "queued" },
    { "id": "uuid-2", "to": "bob@example.com", "status": "queued" }
  ],
  "meta": { "total": 2 }
}
json

List & Get Emails

GET /api/v1/emails • GET /api/v1/emails/:id

Request

Response (single email)

status reflects the raw send state. Engagement is derived from the trackingEvents array returned here — see the Tracking doc.

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "fromEmail": "sender@yourcompany.com",
    "toEmails": ["user@example.com"],
    "ccEmails": null,
    "bccEmails": null,
    "subject": "Welcome!",
    "textBody": "Hello, welcome to our service.",
    "status": "sent",
    "sentAt": "2026-03-18T10:00:05.000Z",
    "createdAt": "2026-03-18T10:00:00.000Z",
    "attachments": [],
    "trackingEvents": [
      {
        "id": "event-uuid-1",
        "type": "open",
        "url": null,
        "ipAddress": "203.0.113.7",
        "userAgent": "Mozilla/5.0",
        "createdAt": "2026-03-18T10:14:22.000Z"
      }
    ],
    "bounces": []
  }
}
json