<Intro>

<EndpointHeader />

<Description>

Sends an email to the recipients you list explicitly in `to`/`cc`/`bcc`. Use it for
transactional sends (receipts, password resets, alerts) and for marketing sends where
you have the recipient addresses on hand; to submit many independent messages in one
request, use [Send a batch of messages](/docs/api/reference/create-email-message-batch)
instead. The `category` field controls suppression policy independently of content:
set it to `marketing` when sending marketing content from this endpoint.

The `202` response means the message is safely accepted for delivery, not yet
delivered. Fetch it by `id` or subscribe to webhook events to follow delivery. The
request never half-succeeds: an unverified sender domain or any field-level
validation failure rejects it immediately with a `422` naming the reason.
Suppression is evaluated per recipient after acceptance: suppressed recipients
surface as `rejected` on the message's recipient list, never as a synchronous
error. New workspaces can send from the shared onboarding domain before verifying
their own; the [quickstart](/docs/get-started/send-your-first-email) covers its
recipient and volume limits.

</Description>

</Intro>

<Payload kind="request">

<Field name="from" type="string or object" required>

<Description>

Sender address, as a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name. Must be from a verified domain in this workspace.

</Description>

<FieldChildren kind="request">

<Field name="email" type="string" prefix="from." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="from.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="to" type="array of string or object" required>

<Description>

Primary recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.

</Description>

<FieldChildren kind="request">

<Field name="email" type="string" prefix="to." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="to.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="cc" type="array of string or object">

<Description>

CC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.

</Description>

<FieldChildren kind="request">

<Field name="email" type="string" prefix="cc." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="cc.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="bcc" type="array of string or object">

<Description>

BCC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.

</Description>

<FieldChildren kind="request">

<Field name="email" type="string" prefix="bcc." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="bcc.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="subject" type="string">

<Description>

Message subject line. Required for inline sends; omit it when sending a `template` (the template supplies the subject).

</Description>

</Field>

<Field name="html" type="string">

<Description>

HTML body. At least one of html or text must be provided.

</Description>

</Field>

<Field name="text" type="string">

<Description>

Plain-text body. At least one of html or text must be provided.

</Description>

</Field>

<Field name="reply_to" type="array of string or object">

<Description>

Reply-To addresses, each a plain email string, an RFC 5322 mailbox string, or an object with an optional display name. RFC 5322 allows multiple. Every recipient reply hits all listed addresses, so 1-2 is typical; the 25 cap exists to prevent runaway header sizes that some MTAs reject.

</Description>

<FieldChildren kind="request">

<Field name="email" type="string" prefix="reply_to." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="reply_to.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="headers" type="object">

<Description>

Custom email headers as key-value pairs (for example `References`, `In-Reply-To`, or your own `X-*` headers). Reserved headers are rejected with a `422`: set the message's addressing and subject through the dedicated fields (`from`, `to`, `cc`, `bcc`, `reply_to`, `subject`) rather than here, and headers the platform generates for you — `Content-Type`, `Content-Transfer-Encoding`, `DKIM-Signature`, `Received`, and `Return-Path` — cannot be overridden. `List-Unsubscribe` and `List-Unsubscribe-Post` are honored as-is on `transactional` sends; on `marketing` sends the platform sets a compliant unsubscribe header for you, so supplying them there is rejected with a `422`. Header values may not contain carriage-return or line-feed characters.

</Description>

</Field>

<Field name="tags" type="array of object">

<Description>

Structured `{name, value}` labels for **filtering and analytics**. Tags become first-class query dimensions: filter the list endpoint by tag name, slice analytics rollups by tag, and surface in webhook payloads. Cap: 20 tags per send. Use tags for low-cardinality dimensions (`category`, `experiment_variant`, `template_id`). For arbitrary structured context that you do not need as a filter dimension, use `metadata` instead.

</Description>

<FieldChildren kind="request">

<Field name="name" type="string" prefix="tags." required>

<Description>

Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.

</Description>

</Field>

<Field name="value" type="string" prefix="tags." required>

<Description>

Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="metadata" type="object">

<Description>

Arbitrary JSON object **stored, returned on API reads, and echoed in webhook payloads**. Path-queryable in analytics (e.g. filter on `metadata.order_id`) but not surfaced as a first-class dashboard filter dimension. Cap: 2 KB serialized. Use metadata for per-send context like internal IDs, foreign keys, and structured payloads you want round-tripped through events. For low-cardinality filterable labels, use `tags` instead.

</Description>

</Field>

<Field name="parameters" type="object">

<Description>

Template variables used to personalize inline content. Tokens in the subject and body (e.g. `{{ first_name }}`) are replaced with these values at send time. Shared across all recipients of this send. A token with no matching key renders empty. Cap: 16 KB serialized. When sending a stored `template`, put the values in `template.parameters` instead.

</Description>

</Field>

<Field name="template" type="object">

<Description>

Send a stored template instead of inline content. When set, omit `subject`/`html`/`text` — the template supplies them; personalize with `template.parameters`.

</Description>

</Field>

<Field name="track_opens" type="boolean">

<Description>

Whether to track open events for this message.

</Description>

</Field>

<Field name="track_clicks" type="boolean">

<Description>

Whether to track click events for this message.

</Description>

</Field>

<Field name="ip_pool_id" type="string">

<Description>

ID of the IP pool to send from (`ipp_` prefix), or `ipp_shared` to route through the shared pool explicitly. Omit to use your organization's default pool. An unknown pool, or a pool with no dedicated IPs available to send from, is rejected with a `422`.

</Description>

</Field>

<Field name="category" type="string">

<Description>

Content classification — independent of which endpoint you use. Controls suppression policy: `marketing` blocks on all suppression reasons (use for marketing content); `transactional` allows delivery through complaint and unsubscribe suppressions (use for receipts, password resets, and similar operational messages). Default: marketing.

</Description>

<Description>

Possible values: `marketing`, `transactional`

</Description>

</Field>

<Field name="in_reply_to_message_id" type="string">

<Description>

Preview feature — threaded replies. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`. When generally available, sets In-Reply-To and References headers automatically.

</Description>

</Field>

<Field name="attachments" type="array of object">

<Description>

File attachments. Bird rejects sends whose estimated generated message size exceeds 20 MB. The estimate is the HTML and text body plus all attachments and inline images measured after base64 encoding. Keep total raw attachment content at or below 15 MB for reliable headroom. In batch sends, this per-message cap still applies and the serialized JSON request body for the whole batch has a hard 20 MB cap. See the EmailAttachment schema for the full field contract.

</Description>

<FieldChildren kind="request">

<Field name="filename" type="string" prefix="attachments." required>

<Description>

Filename shown to the recipient. Required.

</Description>

</Field>

<Field name="content" type="string" prefix="attachments." required>

<Description>

Base64-encoded attachment bytes. Required. Counts toward the 20 MB estimated generated message-size cap after encoding and MIME wrapping.

</Description>

</Field>

<Field name="path" type="string" prefix="attachments.">

<Description>

Preview feature — provide a URL and Bird fetches the attachment for you. Currently unavailable. Use `content` instead. The schema currently requires `content`, so a request with only `path` is rejected with 422 for missing `content`; a request supplying both `content` and `path` is rejected with 422 `UnsupportedEmailFeature` until this preview ships. When generally available: HTTPS-only, single redirect followed and re-validated, private IP ranges blocked, request timeout enforced, fetched content counts toward the 20 MB estimated generated message-size cap after encoding and MIME wrapping.

</Description>

</Field>

<Field name="content_type" type="string" prefix="attachments.">

<Description>

MIME type. Inferred from `filename` extension when omitted. Used to enforce the blocklist of disallowed executable / script types.

</Description>

</Field>

<Field name="content_id" type="string" prefix="attachments.">

<Description>

RFC 2392 Content-ID. When set, the attachment is rendered inline and can be referenced from the HTML body as `<img src="cid:{content_id}"/>`. When omitted, the attachment is rendered as a regular file attachment.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="scheduled_at" type="string">

<Description>

Schedule the message to send at a future time instead of immediately. Must be at least 30 seconds and at most 30 days ahead — outside that range the request is rejected with `422`. The message returns with status `accepted` and shows as `scheduled` on reads until it sends; cancel it before then with the message cancel endpoint. Scheduled sends count against your plan's monthly scheduled-email allowance; exceeding it is rejected with a `422`.

</Description>

</Field>

<Field name="contact_id" type="string">

<Description>

Preview feature — contact-targeted sends. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`.

</Description>

</Field>

<Field name="topic_id" type="string">

<Description>

Preview feature — topic-gated sends. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`. When generally available, a non-empty `topic_id` gates delivery on the recipient's opt-in state for that topic — if the recipient is opt_out, the send is silently suppressed and an `email.suppressed` event fires with `reason: topic_opt_out`.

</Description>

</Field>

</Payload>

<Payload kind="response">

<Field name="id" type="string" required>

<Description>

Message ID.

</Description>

</Field>

<Field name="from" type="object" required>

<Description>

Sender address. `name` is present when a display name was provided on the send.

</Description>

<FieldChildren kind="response">

<Field name="email" type="string" prefix="from." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="from.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="to" type="array of object" required>

<Description>

Primary recipients. Length is the recipient count; use the broadcasts endpoint for audience-targeted sends. Each entry's `name` is present when a display name was provided on the send.

</Description>

<FieldChildren kind="response">

<Field name="email" type="string" prefix="to." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="to.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="cc" type="array of object">

<Description>

CC recipients.

</Description>

<FieldChildren kind="response">

<Field name="email" type="string" prefix="cc." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="cc.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="bcc" type="array of object">

<Description>

BCC recipients.

</Description>

<FieldChildren kind="response">

<Field name="email" type="string" prefix="bcc." required>

<Description>

Email address.

</Description>

</Field>

<Field name="name" type="string" prefix="bcc.">

<Description>

Display name shown alongside the address in mail clients.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="subject" type="string" required>

<Description>

Message subject line.

</Description>

</Field>

<Field name="category" type="string" required>

<Description>

Content classification. Controls suppression policy — `marketing` blocks on all suppression reasons; `transactional` allows delivery through complaint and unsubscribe suppressions.

</Description>

<Description>

Possible values: `marketing`, `transactional`

</Description>

</Field>

<Field name="reply_to" type="nullable array">

<Description>

Reply-To addresses, if set on the send. Empty/null when no Reply-To was provided.

</Description>

</Field>

<Field name="status" type="object" required>

<Description>

Aggregate delivery status derived from recipient states. `scheduled` means the message is queued to send at a future time and has not been dispatched yet. `accepted` means Bird has the send and is preparing to deliver. `processed` means Bird has processed the message and queued it for delivery to the recipient's mail server. `canceled` means a scheduled message was canceled before it was sent.

</Description>

</Field>

<Field name="accepted_count" type="integer" required>

<Description>

Number of recipients currently in the `accepted` state — Bird has the send and is preparing to deliver.

</Description>

</Field>

<Field name="processed_count" type="integer" required>

<Description>

Number of recipients for whom Bird has processed the message and queued it for delivery.

</Description>

</Field>

<Field name="delivered_count" type="integer" required>

<Description>

Number of recipients whose messages were accepted by the remote MTA.

</Description>

</Field>

<Field name="bounced_count" type="integer" required>

<Description>

Number of recipients that resulted in a permanent delivery failure.

</Description>

</Field>

<Field name="complained_count" type="integer" required>

<Description>

Number of recipients that reported spam.

</Description>

</Field>

<Field name="deferred_count" type="integer" required>

<Description>

Number of recipients in transient delivery deferral; the provider is retrying.

</Description>

</Field>

<Field name="rejected_count" type="integer" required>

<Description>

Number of recipients rejected before delivery. See the per-recipient `rejection_reason` field on `GET /v1/email/messages/{message_id}/recipients` for the specific cause (suppression match, transmission failure, generation failure, or policy refusal).

</Description>

</Field>

<Field name="processing_latency_ms" type="nullable integer">

<Description>

Time between Bird accepting the send and the message being processed for delivery, in milliseconds, for the fastest recipient. Null until the first recipient reaches `processed`.

</Description>

</Field>

<Field name="delivery_latency_ms" type="nullable integer">

<Description>

Time between the message being processed and the receiving mail server accepting it, in milliseconds, for the fastest delivered recipient. Null until the first recipient is delivered.

</Description>

</Field>

<Field name="total_latency_ms" type="nullable integer">

<Description>

End-to-end accept → delivered time for the fastest delivered recipient, in milliseconds. Null until the first recipient is delivered.

</Description>

</Field>

<Field name="open_count" type="integer" required>

<Description>

Total open events across all recipients.

</Description>

</Field>

<Field name="click_count" type="integer" required>

<Description>

Total click events across all recipients.

</Description>

</Field>

<Field name="tags" type="array of object">

<Description>

Structured `{name, value}` filter labels applied to this send. See EmailMessageSendRequest for the tags vs metadata distinction.

</Description>

<FieldChildren kind="response">

<Field name="name" type="string" prefix="tags." required>

<Description>

Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.

</Description>

</Field>

<Field name="value" type="string" prefix="tags." required>

<Description>

Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="metadata" type="object">

<Description>

Arbitrary JSON metadata stored on the message object and echoed in webhook payloads. See EmailMessageSendRequest for the tags vs metadata distinction.

</Description>

</Field>

<Field name="attachments" type="array of object">

<Description>

Attachment metadata for the send. Empty when no attachments were included. Raw content is not echoed; when content storage is enabled, download an attachment by its `id` via the message's attachment endpoint.

</Description>

<FieldChildren kind="response">

<Field name="id" type="string" prefix="attachments.">

<Description>

Attachment ID, stable per email send.

</Description>

</Field>

<Field name="filename" type="string" prefix="attachments." required>

<Description>

Filename as shown to the recipient.

</Description>

</Field>

<Field name="content_type" type="string" prefix="attachments.">

<Description>

Resolved MIME type at send time.

</Description>

</Field>

<Field name="size" type="integer" prefix="attachments." required>

<Description>

Decoded size in bytes.

</Description>

</Field>

<Field name="inline" type="boolean" prefix="attachments.">

<Description>

True when the attachment was sent inline via a `content_id` reference in the HTML body, false for regular file attachments.

</Description>

</Field>

<Field name="content_id" type="nullable string" prefix="attachments.">

<Description>

The Content-ID set at send time, when the attachment was inline.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="track_opens" type="boolean" required>

<Description>

Whether open tracking is enabled for this send.

</Description>

</Field>

<Field name="track_clicks" type="boolean" required>

<Description>

Whether click tracking is enabled for this send.

</Description>

</Field>

<Field name="created_at" type="string" required>

<Description>

When the send request was accepted.

</Description>

</Field>

<Field name="thread_id" type="nullable string">

<Description>

Thread this message belongs to. Null until threading is enabled.

</Description>

</Field>

<Field name="in_reply_to_message_id" type="nullable string">

<Description>

The message this one is a reply to, if any.

</Description>

</Field>

<Field name="delivered_at" type="nullable string">

<Description>

When all recipients reached a terminal delivered state, or null if not yet fully delivered.

</Description>

</Field>

<Field name="scheduled_at" type="nullable string">

<Description>

When this message is scheduled to send, for a send created with a future send time. Null for an immediate send. Stays set after the scheduled send fires.

</Description>

</Field>

</Payload>