Sending email

Sending email

There are two ways to send: one message at a time, or a batch of up to 100 in a single request. Both validate each email (valid addresses, a body, a verified from-domain, and that the recipient isn't suppressed) and enforce the usage-only billing gate before queueing.

The email object

Every send uses the same shape:

  • from — sender address on a verified domain (required).
  • fromName — optional display name.
  • to — recipient address (required).
  • cc, bcc, replyTo — optional.
  • subject — required.
  • html and/or text — at least one body is required.
  • templateId — optional template to render instead of an inline body.
  • variables — optional key/value map for substitution.
  • tags — optional comma-separated labels for your own reporting.

Single send

A successful POST /v1/emails returns 202 Accepted with the message id and "status": "queued". If the free tier is exhausted and no payment method is on file (or your spend cap is reached), you'll get 402 Payment Required.

Batch send

POST /v1/emails/batch accepts an emails array of up to 100 items. Each item is validated and queued independently — the response reports how many were accepted vs. rejected, with a per-item error for any that failed:

POST /v1/emails/batch
curl https://api.mailstack.voostack.com/v1/emails/batch \
  -H "Authorization: Bearer ms_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      { "from": "hi@you.com", "to": "a@example.com", "subject": "Hi A", "text": "Hello A" },
      { "from": "hi@you.com", "to": "b@example.com", "subject": "Hi B", "text": "Hello B" }
    ]
  }'
{
  "accepted": 1,
  "rejected": 1,
  "results": [
    { "index": 0, "id": "…", "status": "queued" },
    { "index": 1, "status": "rejected", "error": "Recipient is suppressed." }
  ]
}

Variables & tags

Pass variables to fill in {{ placeholders }} in your subject or body, and tags to label messages for your own segmentation:

Templating an inline body
curl https://api.mailstack.voostack.com/v1/emails \
  -H "Authorization: Bearer ms_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "hi@you.com",
    "to": "user@example.com",
    "subject": "Welcome, {{ name }}",
    "html": "<p>Hi {{ name }}, your code is {{ code }}.</p>",
    "variables": { "name": "Sam", "code": "8421" },
    "tags": "welcome,onboarding"
  }'

Checking status

Call GET /v1/emails/{id} to retrieve a message and its current status. The response includes the lifecycle status, the provider message id once sent, recipients, subject, tags, and timestamps:

{
  "id": "8f3a1c2e-…",
  "fromEmail": "hi@you.com",
  "toEmail": "user@example.com",
  "subject": "Welcome",
  "status": "Sent",
  "providerMessageId": "0102018f…",
  "errorMessage": null,
  "tags": "welcome,onboarding",
  "queuedAt": "2026-06-18T10:00:00Z",
  "sentAt": "2026-06-18T10:00:02Z",
  "createdAt": "2026-06-18T10:00:00Z"
}