Send an email message
Sends an email through the authenticated user’s connected mailbox (Gmail or Outlook). The mailbox is resolved by matching the from address against the user’s connected accounts — the user must have previously completed the OAuth flow for that address. Supports plain-text or HTML bodies, CC/BCC, threading (replies), and attachments stored in R2.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
Payload to send an email through a connected mailbox. The server resolves which mailbox to send from by matching from (and optionally provider) against the authenticated user's connected email accounts.
Email address of the sending mailbox. Must belong to a mailbox the authenticated user has connected via the OAuth flow (Gmail or Outlook). Example: aneesh@tetherai.ca.
"aneesh@tetherai.ca"
Recipient address, or an array of recipient addresses. Each entry may be a bare email (user@x.com) or RFC 5322 formatted ("Name" <user@x.com>).
["recipient@example.com"]Message body. Plain text by default; set isHtml: true to send as HTML. Required.
"Hi — here is the report you asked for."
Tie-breaker used only when the same from address is connected under more than one provider for the same user. Omit in the common case — the server resolves it automatically.
gmail, outlook "gmail"
Optional CC recipients. Same format rules as to.
Optional BCC recipients. Same format rules as to.
Subject line. Optional — when omitted on a reply, the server reuses the subject from the conversation; when omitted on a new thread, (no subject) is used.
"Weekly report"
When true, body is sent as text/html instead of text/plain.
Join key to continue an existing email thread. For Gmail this is the Gmail threadId; for Outlook it is the conversationId. Both are normalised to the same field.
New email: omit this field. The server creates a new conversation and the provider assigns a brand-new thread.
Reply: pass the thread id of the conversation you want to continue. The provider appends the reply to the same thread, and the server auto-fills inReplyTo / references from the latest message in that thread.
How to obtain it:
- From the response of the first
POST /api/email/messages/send— the body returnsthreadId. Persist it for future replies. - From
GET /api/conversation(or/api/conversation/:id) — the conversation'schannelIdentifierfield holds the email thread id for email-channel conversations. - From a stored message — each email message carries
emailMetadata.threadIdon the Message document.
Recipient address alone is not enough to continue a thread, because the same recipient can have multiple unrelated threads.
"gthread-1902a9f3c4b1e0d5"
RFC 5322 In-Reply-To header — the Message-ID of the message being replied to (with angle brackets). Used for threading in recipient clients. If omitted on a reply, the server fills it from the latest message in the thread.
RFC 5322 References header — space-separated Message-IDs forming the reply chain. If omitted on a reply, the server fills it from the latest message in the thread.
Reserved. Must be false or omitted on this endpoint. Private notes are posted through the messages endpoint, not the email send endpoint. Sending true here returns 400.
File attachments to include. Each entry must supply either storageKey (preferred — an R2 storage key produced by the upload endpoint) or a pre-signed url the server can GET.
Response
Email sent. Returns the stored message document, conversation id, and provider thread id.
Success response for POST /api/email/messages/send.
Stored email message document (the message field on the send response).
{
"_id": "665f1a0c0e0a4b001a2c9f60",
"organizationId": "64ee9a8b1e7f2a0011223344",
"conversationId": "665f1a0c0e0a4b001a2c9f70",
"contactId": "665f1a0c0e0a4b001a2c9f01",
"userId": "64ee9a8b1e7f2a0011223399",
"channelType": "email",
"isIncoming": false,
"isInternal": false,
"status": "delivered",
"body": "Hi Jamie — attaching this week's report.",
"attachments": [],
"createdAt": "2026-05-18T12:34:56.000Z",
"updatedAt": "2026-05-18T12:34:56.000Z"
}Internal id of the conversation the message was appended to (or created, on a new thread). Use this with GET /api/conversation/:id to fetch the full conversation.
Provider-side thread id for this email (Gmail threadId / Outlook conversationId). Save this — pass it back as threadId on subsequent POST /api/email/messages/send calls to continue the same thread.
"gthread-1902a9f3c4b1e0d5"