---
title: "Send an email from the org's identity"
method: POST
path: "/emails"
---

# Send an email from the org's identity

`POST /emails`

## Request

- Base URL: `https://worker.openhelm.ai/v1`
- URL: `https://worker.openhelm.ai/v1/emails`
- Auth: HTTP bearer

Sends transactionally from the org's DEFAULT address (orgname@relay.openhelm.ai). To send from a specific inbox — a product's own branded identity, or a named sender like noreply@ — use POST /inboxes/{id}/messages instead. The caller owns approval (e.g. an operator-approved body). Sets a correlation Reply-To so a reply threads back via the email.received webhook. `metadata` is an opaque object echoed verbatim on that webhook.

## Request body

- object
  - `to` union, required: One address or a list. A list is ONE message whose recipients see each other.
    - string, email
    - string[]
  - `cc` string[]
  - `bcc` string[]: Blind copies. Never written into a header the other recipients can read.
  - `subject` string, required
  - `body_markdown` string
  - `body_html` string: Pre-rendered HTML; takes precedence over body_markdown.
  - `text` string
  - `from_name` string: Display name before the address (defaults to the org's name).
  - `reply_to` string, email: Overrides the correlation Reply-To; replies will NOT thread back.
  - `client_id` string: Idempotency key — a repeat returns the original send instead of delivering twice.
  - `metadata` object: Echoed on the reply webhook.

## Response `202`

Accepted

- object
  - `message_id` string
  - `from_address` string
  - `correlation_token` string
  - `status` 'sent' | 'scheduled' | 'pending_approval'
  - `reply_to` object, nullable: Where replies will actually land, and why. `reason` is one of sending_domain (threads on your own domain), relay_fallback (your domain has no confirmed inbound — publish its MX record), override (you supplied one; replies will not be correlated), or none (nothing verified to receive).
    - `address` string, nullable
    - `reason` 'sending_domain' | 'relay_fallback' | 'override' | 'none'
    - `detail` string
  - `suppressed` string[]: Recipients dropped because they are suppressed (hard bounce / complaint). The message WAS delivered to everyone else. Empty on a clean send.

## Other responses

- `400`: Email not configured / invalid body / cap reached / every recipient suppressed

---

[API](https://skmtc.dev/openhelm/apis/openhelm-public-api.md) · [All operations](https://skmtc.dev/openhelm/apis/openhelm-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/openhelm/apis/openhelm-public-api/revisions/2af88dc2f6a7?raw)
