Send Email

Queue one transactional email. Provide exactly one of html, tiptap, or markdown.

MethodPOST
/api/v2/emails

Queues one transactional email. Permission: emails.

Test-mode recipients. Fixture addresses such as [email protected] never send real email. See Test-mode recipients.

Recipient rate guards. The same real mailbox is capped at 5 sends / 10 minutes and 20 / 24 hours. A 429 with code: RECIPIENT_RATE_LIMITED is not the HTTP API rpm limit. See Recipient rate guards.

Exactly one of html, tiptap, or markdown. Markdown is rendered to HTML. Omit text to generate it from the rendered HTML. text: "" skips generation.

Unsupported: attachments, template, topic_id, scheduled_at, react, content, contentType.

Snippets

A tiptap body can embed your organization's saved snippets. Add a snippet node where the block should appear:

{
  "type": "doc",
  "content": [
    { "type": "paragraph", "content": [{ "type": "text", "text": "Hi {{firstName}}," }] },
    { "type": "snippet", "attrs": { "snippetId": "snp_abc123" } }
  ]
}
  • Snippets are expanded once, when the email is queued. Editing the snippet later does not change emails already queued.
  • List ids with the get_email_snippets tool (permission settings). Archived snippets still render.
  • Variables inside the snippet ({{firstName}}, {{unsubscribeUrl}}, …) are filled per recipient like the rest of the body.
  • An unknown id, or one that belongs to another organization, returns 400 validation_error with Snippet not found in this organization: …. Nothing is queued.
  • html and markdown bodies have no snippet syntax; use tiptap.

Body Parameters

NameTypeDescription
fromstringRequired. Sender. Display name is allowed: Acme <[email protected]>. Domain must be verified.
tostring or [string]Required. One recipient. A one-address array is accepted.
subjectstringRequired. Subject line.
htmlstringHTML body. Provide exactly one of html, tiptap, or markdown.
tiptapstring or objectTipTap JSON. Rendered to HTML on send. Can embed saved snippets.
markdownstringMarkdown body. Rendered to HTML on send.
textstringPlain-text body. Omit to generate from HTML. Empty string skips generation.
reply_tostring or string[]Reply-To addresses. Stored as an array. SES uses the first address.
ccstring or string[]Carbon copies.
bccstring or string[]Blind carbon copies.
headersobjectExtra MIME headers.
tags{ name, value }[]Metadata tags stored on the email.
previewstringPreview / preheader text.
tracking{ links: boolean, open: boolean }Open pixel and click wrapping. Both default to true. Set both to false for OTP / magic-link mail.

Options

NameTypeDescription
Idempotency-KeystringOptional header. Repeat the same key to reuse the queued email id.

SDK: pass { idempotencyKey } as the second argument to emails.send.

Response Fields

FieldTypeDescription
idstringQueued email id (eml_...). Fetch the body and last_event with Get Email.

Errors

StatusnameWhen
401missing_api_keyMissing or invalid bearer token
403missing_permissionToken lacks the emails permission
400validation_errorA tiptap snippet id is unknown or belongs to another organization (Snippet not found in this organization: …).
422validation_errorMissing required fields, more than one body format, or unsupported fields
429RECIPIENT_RATE_LIMITEDThis mailbox already hit 5/10 min or 20/24 h, or is on a bounce cooldown. Honor Retry-After. Recipient rate guards.