API Reference

Send Email

The single endpoint behind all email delivery. It works identically for BYOC and Shared SES: the routing decision is made automatically from your sender domain.

Endpoint: POSThttps://api.sendfleet.net/v1/send

Request headers

Required request headers
HeaderValueRequired
X-API-KeyYour API keyYes
Content-Typeapplication/jsonYes

There is no SDK and no client library. Anything that can send an HTTP request with a JSON body can send email, and the examples below cover cURL, Python, Node.js, PHP, Go and Ruby. On WordPress, the official plugin makes this call for every wp_mail() email, so there is no code to write.

Example request

cURL
curl -X POST https://api.sendfleet.net/v1/send \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to":         "alice@example.com",
    "from_email": "hello@yourdomain.com",
    "from_name":  "Your App",
    "subject":    "Your order has shipped",
    "message":    "Hi Alice,\n\nYour order #1234 has shipped!\n\nTrack it: https://track.example.com/1234\n\nThanks,\nYour App",
    "html":       "<p>Hi Alice,</p><p>Your order <strong>#1234</strong> has shipped!</p><p><a href=\"https://track.example.com/1234\">Track your order</a></p>",
    "reply_to":   "support@yourdomain.com",
    "attachments": [
      {
        "filename":     "invoice.pdf",
        "content":      "JVBERi0xLjQK...",
        "content_type": "application/pdf"
      }
    ]
  }'

The smallest body that works

A recipient, a sender and one body. Every other field on this page is optional and can be added later.

Minimal JSON body
{
  "to": "user@example.com",
  "from_email": "hello@yourdomain.com",
  "message": "Thanks for your order!"
}

Request body

All parameters are passed as a JSON object in the request body.

to
string · email, or string[]
Required
Recipient address, or a list of them. Every address must be a valid email address. to, cc and bcc together take at most 50 recipients, the per-message limit of Amazon SES, and an address may appear only once across the three. On Shared SES, to carries exactly one address and the message carries at most 5 in total.
cc
string · email, or string[]
Optional
Optional. Copy recipients, shown to everyone in the Cc header. Same format as to.
bcc
string · email, or string[]
Optional
Optional. Blind-copy recipients. They receive the message but appear in no header, so no other recipient sees them. Same format as to.
from_email
string · email
Optional
Sender address. Its domain must be a verified, send-ready domain in your account. Effectively required in practice: if you omit it, it falls back to your account login email, which is almost never a verified sending domain, and the request fails with domain_not_registered.

This field drives routing. The sending mode of the matching domain, fixed when you added it, decides the path. BYOC domains are delivered through your own AWS SES account; Shared SES domains through SendFleet's managed infrastructure. Same endpoint, same key, either way.
from_name
string
Optional
Display name shown as the sender, rendering as From: Your App <hello@yourdomain.com>. Maximum 156 characters. Omit it and recipients see the bare address.
subject
string
Optional
Subject line, maximum 256 characters. Falls back to (no subject) if omitted, but most spam filters penalise subject-less mail, so always set one in production.
message
string
Optional
Plain-text body. Strongly recommended even when you send html: it is the fallback for clients that do not render HTML, and its absence hurts spam scoring. Required only if you send neither html nor attachments.
html
string · HTML
Optional
HTML body. Clients that can render HTML show this; the rest fall back to message. Use inline CSS only, most email clients strip <style> blocks.
reply_to
string · email
Optional
Where replies should go. Defaults to from_email. Useful when you send from a no-reply address but want replies to reach a monitored inbox.
attachments
object[]
Optional
Optional list of attachments, up to 20 per message. Each entry is an object:

Attachment object fields
FieldTypeRequiredDescription
filenamestringYesOriginal filename including its extension, for example invoice.pdf. Maximum 255 characters.
contentstring · base64YesFile contents as a base64 string. Read the file as binary and encode it — do not pass raw bytes or a data: URI.
content_typestring · MIMENoMIME type, for example application/pdf. Inferred from the filename when omitted. Must be an allowed type and should match the actual contents.

Limits: 25 MB per file, 37 MB total per message, 20 files per message. Executable and script file types are rejected with a 400, this includes .exe, .bat, .cmd, .msi, .js, .jar, .dll, .scr, .vbs, and .ps1 among others, regardless of the content_type you declare. Attachments are held only until the message is delivered, then discarded.

Several recipients

One request sends one message to everyone in to, cc and bcc. Each recipient counts as one send against your monthly allowance, the way Amazon SES counts them, so the example below uses four. A send that needs more than your plan has left is refused whole with 429 usage_limit_exceeded; it never goes to only some of its recipients.

BYOC: one message, four recipients
{
  "to":         ["alice@example.com", "bob@example.com"],
  "cc":         "accounts@example.com",
  "bcc":        ["archive@yourdomain.com"],
  "from_email": "orders@yourdomain.com",
  "subject":    "Your order #1042",
  "message":    "Thanks for your order!"
}
Rules for several recipients
RuleDetail
At most 50 recipientsAcross to, cc and bcc together. More is a 400.
Shared SES: exactly one address in toPut one address in to, as a string or a one-item list, and up to four others in cc or bcc. More than one address in to, or more than 5 recipients in total, returns 403 recipient_limit_exceeded.
No address twiceCompared case-insensitively across all three lists. A repeat is a 400.
Shared SES: one log entry and one event per recipientThe dashboard's email log lists each recipient separately, and every webhook concerns one recipient, named in recipient, under the send's single idempotency_key.
Free plan smoke test: no cc or bccA Shared SES smoke test reaches only your own verified address, so to must be exactly that address and cc and bcc are refused with 403 unauthorized. Free BYOC sending supports both.
Test addresses go alonedelivered@, bounce@ and complaint@ at sendfleet.net must be a send's only recipient.

Successful response

HTTP 200 OK. The email has been accepted and queued, delivery is asynchronous, so this is not a delivery confirmation.

200 OK: BYOC send, delivery tracking on
{
  "success":         true,
  "message":         "Email queued for delivery via your SES account.",
  "message_id":      "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
  "idempotency_key": "3c59dc048e8850243be8079a5c74d079",
  "mode":            "byoc",
  "attachments":     2
}
200 OK: Shared SES send, with deliverability warnings
{
  "success":         true,
  "message":         "Email queued for delivery.",
  "message_id":      "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "idempotency_key": "8f14e45fceea167a5a36dedd4bea2543",
  "mode":            "shared",
  "warnings": [
    "DMARC record not found. Add 'v=DMARC1; p=none;' as a TXT record on _dmarc.yourdomain.com to improve inbox placement."
  ]
}

Response fields

Fields returned on a successful send
FieldTypeDescription
successbooleanAlways true on HTTP 200.
messagestringHuman-readable confirmation. Wording differs between modes; do not branch on it.
message_idstringAn opaque reference for this accepted request. Useful when contacting support about a specific send. It does not appear on any webhook — use idempotency_key for correlation.
idempotency_keystringShared SES, and BYOC with delivery tracking on. The correlation key for this send. The same value appears on every webhook and email log entry for it, so this is what you store against your own records. Absent on an untracked BYOC send.
modestring"byoc" or "shared", the sending mode selected for this request. This does not confirm delivery.
attachmentsnumberCount of attachments accepted. Present only when the request included attachments.
recipientsnumberNumber of recipients across to, cc and bcc, each counted as one send. Present only when there is more than one.
warningsstring[]Optional. Non-blocking deliverability issues such as a missing MAIL FROM or DMARC record. Shared SES only.

Error responses

Sending refusals use the shape below. error is a machine-readable code to branch on;detail is a human-readable explanation. Field validation errors return a map of field names to messages. Authentication, rate-limit and HTTP-level errors can return only detail.

Error response shape
{
  "success": false,
  "error":   "domain_not_verified",
  "detail":  "Domain 'yourdomain.com' is not yet verified. Add both TXT ownership records, then press Verify all records at https://sendfleet.net/dashboard/domains/"
}
Error codes returned by POST /v1/send
HTTPerrorCause
400(field errors)Missing or invalid body fields, including malformed attachments, more than 50 recipients, or a repeated recipient. The body is a map of field name to error messages, not the standard shape above.
403— (no `error` field)Missing, invalid, expired, or revoked API key.
403unauthorizedAccount email unverified, subscription inactive for the required mode, sending unavailable, BYOC not yet connected or SendFleet can no longer access your AWS account, a SendFleet test address sent from a BYOC domain, or a Free plan Shared smoke test addressed to anyone but your own verified address.
403domain_not_registeredThe from_email domain is not in your account.
403domain_not_verifiedDomain ownership has not been confirmed.
403dkim_not_verifiedThe three DKIM CNAME records have not been confirmed.
403domain_mode_mismatchThe domain's sending mode does not match your current plan.
403domain_not_allowedThe API key is scoped to specific domains and the sender domain is not among them.
403recipient_limit_exceededThe message is shaped or sized in a way this account may not send on the path it took. The rule is set by the sending path: 50 across to, cc and bcc on BYOC; on Shared SES, exactly one address in to and 5 in total.
403sending_suspendedAccount sending is temporarily paused or suspended, BYOC sending is paused by the reputation protection you chose, or Shared sending is being re-enabled after a plan change. Check the detail and your dashboard.
429usage_limit_exceededMonthly email quota exhausted for your plan, your own BYOC monthly cap reached, or fewer sends left than the request has recipients.
429—Per-key rate limit exceeded (60 requests per minute).
502attachment_upload_failedAttachments could not be staged for delivery. Retry with backoff.
502queue_errorThe message could not be accepted for delivery. Safe to retry with backoff.
503byoc_not_configuredA BYOC configuration problem on our side. Contact support.
500internal_errorUnexpected error on our side. Retry once, then alert.

See the full Error Codes reference for retry guidance and worked handling examples.

HTML email tips

Email HTML is not browser HTML. Gmail, Outlook, and Apple Mail strip modern CSS and block external resources, so the rules are stricter than you are used to:

HTML email rules of thumb
RuleWhy
Use inline CSS only<style> blocks are stripped by Gmail and many mobile clients.
Use table-based layoutsFlexbox and Grid are ignored by Outlook, which renders with the Word engine.
Host images on absolute HTTPS URLsMany clients block external images by default. Always set meaningful alt text so a blocked image still communicates.
Always include a plain-text bodyIt feeds spam scoring and is what assistive technology and text-only clients read.
Keep the HTML under 100 KBGmail clips messages past roughly 102 KB, hiding whatever is at the bottom — usually your unsubscribe footer.
Test across clients before a large sendRendering varies wildly. Litmus and Email on Acid both cover the major clients.