Send one email as any address that routes into the granted set.

post/v1/emails

Request

  • The document declares no server URL.
  • Auth: one of:
    • OAuth 2 (authorization code, authorization URL /authorize, token URL /oauth/token, scopes: email.send)
    • HTTP bearer

Headers

Idempotency-Keystring

Request body

fromstring required

Required — there is no default sender, ever. The send is authorized by routing: mail to this address must route into SOME mailbox in the caller's granted set ("you can send from anyone you can receive from"), and that routed granted mailbox becomes the send's accounting identity — its rate limit, its idempotency scope, its audit row, and where the sent copy files (which is where the reply will land). When the address routes into several granted mailboxes, the FIRST in mailbox-key order is the accounting identity — deterministic, and independent of the order grants were made. An address that routes into no granted mailbox is refused with 422, never rewritten. Routing is resolved as inbound mail is: the exact address, then the address without its +tag, then the domain's catch-all (*@domain) — so a catch-all's holders may send as any address on its domain nobody else has claimed, and nobody may send as *@domain itself.

replyTostring

One email address.

⚠️ Bounded because we STORE it. RFC 5321 §4.5.3.1.1 caps a path at 256 octets, which is the same number the inbound envelope enforces. The recipient COUNT was capped and the length of each was not, so fifty addresses of unbounded length were joined into one sent_emails.to_addr column and one Durable Object to_addrs blob. The domain refuses these too — this arm exists so a caller is told at the edge rather than by a 422 from three layers down.

subjectstring

RFC 5322 caps a subject line at 998 characters.

textstring

Per-part body cap — generous for transactional mail, bounds abuse and cost.

htmlstring

Per-part body cap — generous for transactional mail, bounds abuse and cost.

inReplyTostring

A threading header value that still fits one RFC 5322 §2.1.1 line.

referencesstring

A threading header value that still fits one RFC 5322 §2.1.1 line.

templateIdstring

Render a stored template instead of inline content. Naming both is a 400, never a guess. Resolved against the granted mailbox the from routes into — the same mailbox that accounts for the send.

dataobject

Merge variables for templateId.

draftIdstring

The draft this sends, if it was one. Once the send is accepted the draft is gone from the mailbox the send went from, its files with it — so a sent message's draft never lingers, and a refused send keeps it. Naming a draft that is not there changes nothing about the send, unless attachments names its files.

Response

The request has succeeded.

idstring required
messageIdstring nullable required
status'sent' | 'failed' | 'rate_limited' | 'in_flight' | 'rejected' required

Every state a send outcome can report.

errorstring nullable required

Why the transport refused it. Null on success.

replayedboolean

Present when an Idempotency-Key replayed a send that had already gone.

Changes

No recorded changes to this operation across all 1 revision of this API.