Skip to main content
POST
/
api
/
email
/
send
Send outbound email
curl --request POST \
  --url https://dev.exante.app/api/email/send \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "from_account_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "to": [
    "<string>"
  ],
  "subject": "<string>",
  "cc": [
    "<string>"
  ],
  "bcc": [
    "<string>"
  ],
  "body_text": "<string>",
  "body_html": "<string>",
  "attachments": [
    {
      "filename": "<string>",
      "content_type": "<string>",
      "data_base64": "<string>"
    }
  ],
  "context_type": "<string>",
  "context_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "idempotency_key": "<string>"
}
'
{
  "outbound_email_uid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "provider_message_id": "<string>",
  "provider_thread_id": "<string>",
  "status": "<string>",
  "sent_at": "2023-11-07T05:31:56Z"
}
Send an email immediately through a connected Gmail account. The email is dispatched right away and tracked as an OutboundEmail record for audit and correlation purposes. You can use this endpoint in two modes:
  • Send an existing draft by draft_uid
  • Send a newly composed email by passing sender/recipient/content fields
  • Reply in an existing thread by passing reply_to_message_uid (Gmail threading)

When to use

Use this endpoint for all send operations. If you need to:
  • Resolve dynamic fields first → Use Prepare Email then send
  • Save for later editing → Use Create Draft instead
  • Schedule for future delivery → Create a draft with planned_send_at

Send modes

Option A: send an existing draft

Provide only draft_uid:
{
  "draft_uid": "draft-uuid-here"
}

Option B: send a newly composed email

Provide full email details (current behavior):
{
  "from_account_id": "a1b2c3d4-...",
  "to": ["customer@example.com"],
  "cc": ["accounting@mycompany.com"],
  "subject": "Invoice INV-2024-001 - Payment Reminder",
  "body_text": "Hi,\n\nThis is a friendly reminder...",
  "body_html": "<html><body><p>Hi,</p><p>This is a friendly reminder...</p></body></html>",
  "context_type": "invoice",
  "context_id": "invoice-uuid-here",
  "idempotency_key": "reminder-inv-2024-001-attempt-1"
}

Option C: reply in an existing Gmail thread

Provide the same fields as a fresh send, plus reply_to_message_uid pointing at the existing message you are replying to. For replies, the backend derives the sender inbox server-side from the conversation context (conversation_owner_email), so from_account_id is not required and is ignored if provided.
{
  "to": ["customer@example.com"],
  "subject": "RE: Invoice INV-2024-001 - Payment Reminder",
  "body_html": "<p>Following up here…</p>",
  "reply_to_message_uid": "message-uuid-you-are-replying-to"
}
When reply_to_message_uid is provided, the backend resolves Gmail threading parameters from the stored message + conversation integration mapping and sends using:
  • Gmail threadId
  • RFC headers In-Reply-To and References

How it works

  1. Routing - If draft_uid is provided, the existing draft is loaded and sent
  2. Validation - Without draft_uid, to and subject are required. from_account_id is required only for non-reply fresh sends (i.e. when reply_to_message_uid is not provided).
  3. Idempotency - For fresh sends, idempotency_key can return an existing result
  4. Gmail send - The email is dispatched through Gmail (optionally threaded if reply_to_message_uid is provided)
  5. Status update - On success, status becomes SENT with provider IDs populated

Required parameters

ModeRequired fields
Send draftdraft_uid
Send freshfrom_account_id, to, subject
Send reply (threaded)to, subject, reply_to_message_uid

Optional parameters

ParameterDescription
draft_uidUUID of an existing draft to send
reply_to_message_uidUUID of an existing EmailMessage to reply to (enables Gmail threading via threadId + reply headers)
cc / bccAdditional recipients
body_textPlain text email body
body_htmlHTML email body (takes precedence for rich email clients)
attachmentsArray of attachments with filename, content_type, and data_base64
context_type / context_idLink to a domain entity (e.g., invoice)
idempotency_keyUnique key to prevent duplicate fresh sends

Gmail threading notes

reply_to_message_uid is validated and resolved server-side. A threaded reply requires:
  • The referenced message exists and has a resolvable RFC Message-ID header
  • The conversation has a Gmail thread mapping available (used to derive provider_thread_id)
  • The conversation has a resolvable inbox owner email (used to derive the sender inbox for the reply)
If any required threading inputs cannot be resolved, the endpoint returns a validation error with details.

Response

On success, you receive the OutboundEmail record details:
{
  "outbound_email_uid": "oe-uuid",
  "provider_message_id": "18abc123def",
  "provider_thread_id": "18abc123def",
  "status": "sent",
  "sent_at": "2024-03-25T10:30:00Z"
}
If the Gmail API call fails, the status will be FAILED and the error will be recorded. The endpoint will return an error response.

What’s not (explicitly) supported / enforced

  • Attachments are accepted as base64 (attachments[].data_base64), but size/type limits are not explicitly enforced at the API-doc level and may be constrained by upstream request limits or provider behavior.
  • Inline/CID attachments are not explicitly supported/enforced by this endpoint.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json
from_account_id
string<uuid>
required
to
string[]
required
subject
string
required
cc
string[]
bcc
string[]
body_text
string
body_html
string
attachments
object[]
context_type
string
context_id
string<uuid>
idempotency_key
string

Response

Email send accepted

outbound_email_uid
string<uuid>
provider_message_id
string
provider_thread_id
string
status
string
sent_at
string<date-time>