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
| Method | Path | Permission |
|---|---|---|
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!"
}
}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 everyemail.*webhook. Lets you join events to your own records without storing Sendy ids.track_opens— defaulttrue. Set to false to skip the open-tracking pixel.track_clicks— defaulttrue. 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
}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
}
}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 }
}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": []
}
}