Send email
POST /email/messages accepts raw content or a template, never both, and returns 202 with a message you can poll.
Send a message
POST /email/messages accepts either raw content or a template, never both. With raw content, subject is required alongside html or text. With template_id, the body comes from the active version of the template and variables fills the placeholders.
curl -X POST https://api.qsendyx.com/api/v1/email/messages \
-H "Authorization: Bearer $QSENDYX_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"from": { "email": "you@yourcompany.com", "name": "Your Company" },
"to": [{ "email": "user@example.com" }],
"subject": "Welcome aboard",
"html": "<h1>You are in.</h1>"
}'{
"from": { "email": "you@yourcompany.com" },
"to": [{ "email": "user@example.com" }],
"template_id": "019f70c2-2b41-7a5e-9c3e-2f1a8d55b310",
"variables": { "name": "Ana", "order_id": "A-1042" }
}Request fields
| Field | Notes |
|---|---|
| from | Object with email and optional name. Must be a verified domain or sender. |
| to | Array of recipients, at least one. |
| reply_to | Object with email and optional name. Sets the Reply-To header — where answers go. |
| reply_to_list | Array of the same objects, up to 1000. Mutually exclusive with reply_to. |
| subject | Required unless template_id is present, where it overrides the template. |
| html / text | Raw content. Mutually exclusive with template_id. |
| template_id / variables | Template mode. Templates are sandboxed — they never execute code. |
| type | transactional (default) or marketing. Separate identities, separate reputation. |
| send_at | Schedules the send. UTC. |
| tags / metadata | Yours. Returned on events, useful for correlation. |
| tracking | Per-message opens and clicks toggles. |
Where replies go
reply_to sets the Reply-To header of the delivered message — the address the recipient reaches when they hit Reply. It is independent of from: the message can be signed by no-reply and still be answerable. Send an object with email and an optional name, the same shape as from; the name travels into the header as the display name.
{
"from": { "email": "no-reply@yourcompany.com", "name": "Your Company" },
"to": [{ "email": "support@yourcompany.com" }],
"reply_to": { "email": "ana@customer.com", "name": "Ana Ribeiro" },
"subject": "New contact form submission",
"text": "Ana wrote: my invoice has the wrong address."
}This matters most for the two halves of a contact form. The copy that goes to your team should reply to whoever wrote in; the confirmation that goes back to them should reply to your monitored inbox. Without it, both ends answer into a no-reply address and the message is lost — people reply to "do not reply" messages anyway, to add a detail or attach a document.
Reply-To is an address list in RFC 5322, so more than one address is legal. Use reply_to_list for that, with up to 1000 entries of the same shape. The two fields are mutually exclusive: sending both is a 422, never a silent pick — choosing for you would send a reply somewhere you did not ask for.
{
"from": { "email": "no-reply@yourcompany.com", "name": "Your Company" },
"to": [{ "email": "ana@customer.com" }],
"reply_to_list": [
{ "email": "support@yourcompany.com", "name": "Support" },
{ "email": "billing@yourcompany.com" }
],
"subject": "We received your request",
"text": "Reply to this message and both teams will see it."
}Response and status
{
"id": "019f7141-46ac-76c3-8276-042f38c68cd8",
"status": "queued",
"channel": "email",
"to": "user@example.com",
"from": "you@yourcompany.com",
"type": "transactional",
"created_at": "2026-07-17T18:05:31Z",
"estimated_cost_micros": 0,
"currency": "USD"
}Poll GET /email/messages/{id} for the current state, or — better — subscribe to webhooks and let the status come to you.
curl https://api.qsendyx.com/api/v1/email/messages/019f7141-46ac-76c3-8276-042f38c68cd8 \
-H "Authorization: Bearer $QSENDYX_TOKEN"