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
Prepare with POST /v1/attachments/uploads, Idempotency-Key, mailboxId, filename, mediaType, sizeBytes and hexadecimal SHA-256. PUT bytes with the returned headers to the ten-minute URL, then POST /v1/attachments/uploads/{uploadId}/complete. Repeated completion returns the same attachment ID. GET /v1/attachments/{attachmentId}/download-url provides a sixty-second stream; each invocation rechecks current authorization and message visibility. Never forward an API key to storage or log signed URLs. Individual files and full MIME emails are limited to 25 MiB; MIME includes base64 overhead. Legacy JSON transfers remain for small files. No antivirus scanning is implemented
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.