Skip to content
AI Inbx
Esc
↑↓navigate↵open⌘Jpreview

Send an email

Sends an email — or, with draft: true, writes it for a person to review and send. Requires a from address on a verified domain or a connected mailbox, and at least one of html or text. thread_id continues a conversation; to answer a message AI Inbx has not seen — mail from before a migration, or from another provider — name it in in_reply_to and references instead. Recipients on a matching suppression list are dropped and reported in suppressed; a pacing rule that holds the message is reported in pacing. Pass Idempotency-Key so a retry after a timeout replays the original send instead of sending twice. A workspace with no plan fails with 402 plan_required, and one that has used its plan’s emails for the month with 402 allowance_reached.

POST/emails
Authorization
AuthorizationBearer token (API key) · headerrequired

Pass an AI Inbx API key as a Bearer token.

Header parameters
Idempotency-Keystring

Makes a send safe to retry. Reuse only for the same request body.

min length 1 · max length 255
AIInbx-Workspacestring

Workspace id from GET /workspaces, for an OAuth token that reaches several.

min length 1
Request body
requiredapplication/json
fromstring | object

The sender, you@yourdomain.com or Name <you@yourdomain.com>, on a verified domain or a connected mailbox. Required, except from a connection made an inbox: left out, it sends as its inbox on the thread in thread_id — the one mail on the thread last went through, on a tie the one the thread is filed under — or as its only one. With several and none of them on the thread, it has to be named.

Show properties
Any of:
string
string
object
namestring
min length 1 · max length 200
addressstring<email>required
matches ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
tostring<email> | string<email>[]required

Recipients: one address or a list, at most 100.

Show properties
Any of:
string<email>
string<email>
string<email>[]
Array of string<email>
string<email>
subjectstringrequired

The subject line.

max length 998
thread_idstring

Continue this thread: the email answers its latest message, and In-Reply-To and References are written from it.

matches ^[a-z]+_[0-9a-f]{32}$
in_reply_tostring

The Message-ID this email answers, with or without angle brackets — for a reply to a message AI Inbx may never have seen. When it names an email of yours the send joins that thread; otherwise it opens one. Not with thread_id.

max length 982 · matches ^(?:<[\x21-\x3b\x3d\x3f-\x7e]+>|[\x21-\x3b\x3d\x3f-\x7e]+)$
referencesstring[]

The Message-IDs of the conversation so far, oldest first, written as References. in_reply_to is added at the end when it is not already there, and stands alone when this is left out. Not with thread_id.

max items 100
ccstring<email> | string<email>[]

Cc recipients: one address or a list, at most 100.

Show properties
Any of:
string<email>
string<email>
string<email>[]
Array of string<email>
string<email>
bccstring<email> | string<email>[]

Bcc recipients, hidden from the others: one address or a list, at most 100.

Show properties
Any of:
string<email>
string<email>
string<email>[]
Array of string<email>
string<email>
reply_tostring<email> | string<email>[]

Where replies go (Reply-To), when not to the sender: one address or a list, at most 100.

Show properties
Any of:
string<email>
string<email>
string<email>[]
Array of string<email>
string<email>
attachmentsobject[]

Files to attach, at most 20: filename, content_type and content in base64, and a cid to make one an inline image.

max items 20
Show properties
Array of object
filenamestringrequired
min length 1 · max length 255
content_typestringrequired
min length 1 · max length 255
contentstringrequired
max length 4000000
cidstring
max length 998
headersobject

Extra headers to write on the message. Message-ID, In-Reply-To and References are the API's to write and are refused.

suppression_keystring

The suppression list the send is checked against, besides the workspace-wide * list.

min length 1 · max length 256
pacingobject

The send's say over pacing: skip: true goes past every rule, count: false uses up none of their limits.

Show properties
skipboolean
countboolean
trackingobject

Overrides the sending domain's tracking settings for this email. Only mail sent from a domain is tracked: true on a send from a connected mailbox is refused with tracking_unavailable.

Show properties
opensboolean

Whether opens are tracked on this email. Omit to follow the domain's tracking.opens.

clicksboolean

Whether links are rewritten to track clicks on this email. Omit to follow the domain's tracking.clicks.

scheduled_atstring<date-time>

When to send, as an ISO 8601 time, at most 30 days out. On a draft, the time proposed for it.

matches ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
draftboolean

Keep it as a draft for a person to review: nothing is sent until it is sent with POST /emails/{id}/send or from the console, at draft.review_url. A draft uses none of the plan's emails until then.

htmlstring

The HTML body.

max length 2000000
textstring

The plain-text body.

max length 2000000
unsubscribeboolean

Marks the email non-essential: it carries one-click unsubscribe headers, and optional suppressions apply to it. One recipient only.

Responses
200

An idempotent request replayed the existing email.

idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
thread_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
space_idstring | nullrequired

Which space a resource is in. Null is the workspace itself — what every resource of a workspace that has no spaces says.

Show properties
Any of:
string
string
null
null
directionstringrequired
Allowed:inboundoutbound
statusstringrequired
Allowed:draftscheduledcanceleddiscardedqueuedsendingsentdeliveredbouncedcomplainedfailedreceived
fromobjectrequired
Show properties
namestring | null
Show properties
Any of:
string
string
null
null
addressstring<email>required
matches ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
tostring<email>[]required
ccstring<email>[]
bccstring<email>[]
reply_tostring<email>[]
subjectstringrequired
snippetstringrequired
htmlstring | null
Show properties
Any of:
string
string
null
null
textstring | null
Show properties
Any of:
string
string
null
null
categorystring | nullrequired
Show properties
Any of:
string
string
null
null
verdictsobject | nullrequired
Show properties
Any of:
object
spamstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
spfstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
dkimstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
dmarcstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
null
null
suppression_keystring | nullrequired
Show properties
Any of:
string
string
null
null
message_idstringrequired

The RFC Message-ID, without angle brackets.

in_reply_tostring | nullrequired

The Message-ID of the message this one answers, without angle brackets. Null when it answers none.

Show properties
Any of:
string
string
null
null
idempotency_keystring | nullrequired
Show properties
Any of:
string
string
null
null
created_atstring<date-time>required

When it took its place in its thread. A draft's moves to when it is sent — draft.drafted_at keeps when it was written.

matches ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
scheduled_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
sent_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
draftobject | nullrequired
Show properties
Any of:
object
drafted_atstring<date-time>required
matches ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
edited_atstring<date-time> | nullrequired

When its content last changed before it was sent. Null when it went as written.

Show properties
Any of:
string<date-time>
string<date-time>
null
null
review_urlstring<uri> | nullrequired

Where a person reviews, edits and sends it in the console.

Show properties
Any of:
string<uri>
string<uri>
null
null
null
null
attachmentsobject[]
Show properties
Array of object
idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
filenamestringrequired
content_typestringrequired
sizeintegerrequired
min 0 · max 9007199254740991
cidstring | nullrequired
Show properties
Any of:
string
string
null
null
download_urlstring<uri> | nullrequired

Signed URL for the original bytes, good until expires_at. Opens without the API key, so treat it as a secret — and do not send the key to it: storage answers a request that carries an Authorization header with 400. To keep a reference, store the attachment id and call GET /attachments/{id}. Null when the bytes are gone.

Show properties
Any of:
string<uri>
string<uri>
null
null
expires_atstring<date-time> | nullrequired

When download_url and preparation.content_url stop working — an hour after the response. Read the email again, or call the download endpoint with the attachment ID, for fresh ones.

Show properties
Any of:
string<date-time>
string<date-time>
null
null
preparationobject | nullrequired
Show properties
Any of:
object
statusstringrequired
Allowed:readypartialunsupportedfailed
formatstring | nullrequired
Show properties
Any of:
string
string
null
null
pagesinteger | nullrequired
Show properties
Any of:
integer
integer
null
null
warningsstring[]required
content_urlstring<uri> | nullrequired

Signed URL for the prepared text, good until the attachment's expires_at. Opens without the API key — and only without it: storage answers a request that carries an Authorization header with 400. Null when there is no prepared text.

Show properties
Any of:
string<uri>
string<uri>
null
null
textstring | null
Show properties
Any of:
string
string
null
null
null
null
suppressedstring<email>[]required
pacingobject | nullrequired
Show properties
Any of:
object
held_byobjectrequired
Show properties
One of:
object
kindstringrequired
object
kindstringrequired
rule_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
object
kindstringrequired
rule_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
estimated_send_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
null
null
201

The email was accepted.

idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
thread_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
space_idstring | nullrequired

Which space a resource is in. Null is the workspace itself — what every resource of a workspace that has no spaces says.

Show properties
Any of:
string
string
null
null
directionstringrequired
Allowed:inboundoutbound
statusstringrequired
Allowed:draftscheduledcanceleddiscardedqueuedsendingsentdeliveredbouncedcomplainedfailedreceived
fromobjectrequired
Show properties
namestring | null
Show properties
Any of:
string
string
null
null
addressstring<email>required
matches ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
tostring<email>[]required
ccstring<email>[]
bccstring<email>[]
reply_tostring<email>[]
subjectstringrequired
snippetstringrequired
htmlstring | null
Show properties
Any of:
string
string
null
null
textstring | null
Show properties
Any of:
string
string
null
null
categorystring | nullrequired
Show properties
Any of:
string
string
null
null
verdictsobject | nullrequired
Show properties
Any of:
object
spamstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
spfstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
dkimstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
dmarcstring | nullrequired

PASS, FAIL, GRAY or PROCESSING_FAILED. Null when this check was not reported.

Show properties
Any of:
string
string
null
null
null
null
suppression_keystring | nullrequired
Show properties
Any of:
string
string
null
null
message_idstringrequired

The RFC Message-ID, without angle brackets.

in_reply_tostring | nullrequired

The Message-ID of the message this one answers, without angle brackets. Null when it answers none.

Show properties
Any of:
string
string
null
null
idempotency_keystring | nullrequired
Show properties
Any of:
string
string
null
null
created_atstring<date-time>required

When it took its place in its thread. A draft's moves to when it is sent — draft.drafted_at keeps when it was written.

matches ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
scheduled_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
sent_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
draftobject | nullrequired
Show properties
Any of:
object
drafted_atstring<date-time>required
matches ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
edited_atstring<date-time> | nullrequired

When its content last changed before it was sent. Null when it went as written.

Show properties
Any of:
string<date-time>
string<date-time>
null
null
review_urlstring<uri> | nullrequired

Where a person reviews, edits and sends it in the console.

Show properties
Any of:
string<uri>
string<uri>
null
null
null
null
attachmentsobject[]
Show properties
Array of object
idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
filenamestringrequired
content_typestringrequired
sizeintegerrequired
min 0 · max 9007199254740991
cidstring | nullrequired
Show properties
Any of:
string
string
null
null
download_urlstring<uri> | nullrequired

Signed URL for the original bytes, good until expires_at. Opens without the API key, so treat it as a secret — and do not send the key to it: storage answers a request that carries an Authorization header with 400. To keep a reference, store the attachment id and call GET /attachments/{id}. Null when the bytes are gone.

Show properties
Any of:
string<uri>
string<uri>
null
null
expires_atstring<date-time> | nullrequired

When download_url and preparation.content_url stop working — an hour after the response. Read the email again, or call the download endpoint with the attachment ID, for fresh ones.

Show properties
Any of:
string<date-time>
string<date-time>
null
null
preparationobject | nullrequired
Show properties
Any of:
object
statusstringrequired
Allowed:readypartialunsupportedfailed
formatstring | nullrequired
Show properties
Any of:
string
string
null
null
pagesinteger | nullrequired
Show properties
Any of:
integer
integer
null
null
warningsstring[]required
content_urlstring<uri> | nullrequired

Signed URL for the prepared text, good until the attachment's expires_at. Opens without the API key — and only without it: storage answers a request that carries an Authorization header with 400. Null when there is no prepared text.

Show properties
Any of:
string<uri>
string<uri>
null
null
textstring | null
Show properties
Any of:
string
string
null
null
null
null
suppressedstring<email>[]required
pacingobject | nullrequired
Show properties
Any of:
object
held_byobjectrequired
Show properties
One of:
object
kindstringrequired
object
kindstringrequired
rule_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
object
kindstringrequired
rule_idstringrequired
matches ^[a-z]+_[0-9a-f]{32}$
estimated_send_atstring<date-time> | nullrequired
Show properties
Any of:
string<date-time>
string<date-time>
null
null
null
null
400

The request is invalid.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
401

The API key is missing or invalid.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
402

The workspace has no plan (plan_required), or its plan's allowance is used up (allowance_reached).

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
403

The API key or token does not have the required scope, or the token is connected as an inbox and the operation is not one an inbox may use.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
404

The requested resource does not exist.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
409

The request conflicts with the resource's current state.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
413

The request body or attachments are too large.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
415

The request body is not JSON.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
422

The request body failed validation.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
429

The organisation's request budget is spent (too_many_requests), or an upstream mail provider is throttling (rate_limited).

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
500

An internal error occurred.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
502

An upstream mail provider failed.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
503

The service is temporarily unavailable.

typestringrequired
titlestringrequired
statusintegerrequired
min -9007199254740991 · max 9007199254740991
detailstringrequired
codestringrequired
request_idstringrequired
issuesobject[]
Show properties
Array of object
pathstringrequired
messagestringrequired
Request
import AIInbx from "aiinbx"

const aiinbx = new AIInbx()

const response = await aiinbx.emails.send({
  from: "hello@mail.example.com",
  to: "customer@example.net",
  subject: "Your order is confirmed",
  text: "Thanks for your order. Reply to this email if you need help.",
})
Response
{
  "id": "eml_0123456789abcdef0123456789abcdef",
  "thread_id": "thr_0123456789abcdef0123456789abcdef",
  "space_id": null,
  "direction": "outbound",
  "status": "queued",
  "from": {
    "address": "hello@mail.example.com"
  },
  "to": [
    "customer@example.net"
  ],
  "subject": "Your order is confirmed",
  "snippet": "Thanks for your order. Reply to this email if you need help.",
  "category": null,
  "verdicts": null,
  "suppression_key": null,
  "message_id": "01234567-89ab-cdef-0123-456789abcdef@mail.example.com",
  "in_reply_to": null,
  "idempotency_key": "order-123-confirmation",
  "created_at": "2026-09-05T10:00:00Z",
  "scheduled_at": null,
  "sent_at": null,
  "draft": null,
  "suppressed": [],
  "pacing": null
}