Skip to documentation

API · Emails

Send Email

Send an email from a verified sender (requires sending or full access). Suppressed recipients are excluded, and unsubscribe headers are not added automatically.

POST/emailsSending or full access

Request parameters

ParameterTypeDescription
Idempotency-Key
header · optional
string
1–256 characters
Makes the request safe to retry. See Idempotency.
from
body · optional
string | nullVerified sender address, optionally formatted as Name <sender@example.com>, or omitted when supplied by a published template.
to
body · required
string | (string)[]
For string: At least 1 character
For (string)[]: At least 1 item
Recipient address or array of addresses, with up to 50 recipients across to, cc, and bcc.
subject
body · optional
string | nullEmail subject, required unless supplied by a published template.
cc
body · optional
string | (string)[] | nullCc address or array of addresses, counted toward the 50-recipient total. Email address or array of up to 50 addresses.
bcc
body · optional
string | (string)[] | nullBcc address or array of addresses, counted toward the 50-recipient total. Email address or array of up to 50 addresses.
reply_to
body · optional
string | (string)[] | nullReply-to address or array of up to 50 addresses. Email address or array of up to 50 addresses.
html
body · optional
string | nullHTML content, sharing a 900000-byte UTF-8 limit with text and headers; provide HTML or text unless using a template.
text
body · optional
string | nullPlain text content, sharing a 900000-byte UTF-8 limit with HTML and headers; provide text or HTML unless using a template.
headers
body · optional
object | nullUp to 50 custom headers, counted toward the combined 900000-byte content limit.
scheduled_at
body · optional
string | nullSend time in ISO 8601 or natural language, up to 30 days ahead, using UTC when unzoned and sending immediately for past times. Send time in ISO 8601 or natural language, up to 30 days ahead, using UTC when unzoned; past times send immediately and rescheduling requires a future time.
attachments
body · optional
(object)[] | nullAttachments with a combined encoded size of at most 40 MiB, within the 42 MiB JSON request limit and your installation’s proxy limits.
attachments[].content
body · optional
stringBase64 file content with whitespace ignored, limited to 40 MiB of encoded content across all attachments.
attachments[].filename
body · optional
string
1–255 characters
Attachment filename, inferred from the URL path when omitted.
attachments[].path
body · optional
stringPublic HTTPS URL with up to three redirects to public HTTPS destinations; private addresses are rejected.
attachments[].content_type
body · optional
string | nullAttachment MIME type, inferred from the filename when omitted.
attachments[].content_id
body · optional
string | null
1–78 characters
Content ID for embedding inline images using cid references (e.g., cid:image001).
tags
body · optional
(object)[] | nullUp to 48 tags to associate with the email.
tags[].name
body · required
stringTag name of 1–256 ASCII letters, numbers, underscores, or hyphens.
tags[].value
body · required
stringTag value of 1–256 ASCII letters, numbers, underscores, or hyphens.
template
body · optional
object | nullPublished template to render instead of HTML or text; non-null html or text cannot be combined with a template.
template.id
body · required
stringPublished template id or alias.
template.variables
body · optional
object | nullTemplate variable values, each a string or number matching the variable’s definition.
topic_id
body · optional
string | nullTopic ID used to check each recipient’s subscription before delivery; explicit choices override defaults and unsubscribed recipients fail.

Request example

Set OPENSEND_BASE_URL=https://api.example.com and OPENSEND_API_KEY=os_replace_me on your server.

bash
curl -X POST "$OPENSEND_BASE_URL/emails" \
  -H "Authorization: Bearer $OPENSEND_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"from":"Acme <hello@example.com>","to":["you@example.net"],"subject":"Welcome","html":"<p>Hello.</p>"}'

Response

200 · application/json. Example IDs stand for IDs returned by your installation.

json
{
  "id": "YOUR_ID"
}

Behavior and errors

A returned ID means queued, not delivered. Content and custom headers total at most 900,000 UTF-8 bytes. Actual request-size limits also depend on your Convex/proxy deployment. Use topic_id for per-address preference checks at delivery. Transactional sends do not automatically add unsubscribe headers.

Use a sending or full-access credential. Resource IDs belong to your team; an unknown or foreign resource returns 404. See authentication, errors, rate limits, and compatibility for the shared contract.