Skip to content
Developer platform · Messages

Send email exactly once

Every send names an authorized mailbox and requires an idempotency key so network retries cannot create duplicate messages.

Queue a message

A 202 response means the message is durably queued. Track message.sent, message.delivered, message.bounced, or message.failed afterward.

                        const queued = await maildeck.messages.send(
  {
    fromMailboxId: 'mailbox_id',
    to: ['customer@example.com'],
    subject: 'Your receipt',
    text: 'Thanks for your order.',
  },
  { idempotencyKey: crypto.randomUUID() },
);
                      

Request contract

fromMailboxId must identify a mailbox owned by the credential tenant. to requires 1–50 valid addresses; cc and bcc accept up to 50 each. subject accepts up to 998 characters, text up to 1,000,000, html up to 2,000,000, and attachmentIds up to 20 UUIDs. Ownership and current plan capacity are checked before queueing.

Asynchronous delivery process

The API reserves idempotency for 24 hours, creates the outbound job, writes audit context, and returns { id, object: "message", status: "queued" }. An outbound worker builds MIME, stores the sent object, submits it through SES, and emits message.sent. SES delivery notifications later become message.delivered, message.bounced, or message.failed.

  • 202 queued is durable acceptance, not recipient delivery
  • The returned id correlates API, job, events, webhooks, and support logs
  • Poll canonical state only for reconciliation; use webhooks for low latency

Retry safely

Use 8–255 opaque characters and reuse the same Idempotency-Key only with the byte-equivalent logical request. A completed retry returns the original status and object ID with Idempotent-Replayed: true. A different body returns idempotency_conflict; a still-running first request returns idempotency_pending.

Add attachments before sending

POST /v1/attachments receives mailboxId, filename, mediaType, and contentBase64. Each decoded object is limited to 25 MB and must belong to the same tenant/mailbox context. Keep returned attachment IDs and include them in attachmentIds. Downloads require attachments:read and a clean scan state.

Update message state

PATCH /v1/messages/{messageId} requires messages:write plus mailboxId and at least one mutation: isRead, isStarred, or folder. Supported folders are inbox, sent, archive, spam, and trash. Successful mutations emit message.updated so Webmail, API consumers, and webhook receivers converge on the same state.

Next step

Create the first mailbox at no cost.

Start freeLog in