POST /messages sends immediately. To save incomplete content, autosave changes,
or review attachments before sending, use Drafts. Drafts
do not appear in message, thread, or search results until sent.
List messages
Path parameters
Query parameters
start_datetime, end_datetime, and tz filter on created_at. Both bounds are optional and non-breaking — omit them for unchanged behavior. See Filtering by date.
Response (200)
JSON
Code examples
Get message
body_text/body_html include any automatically applied custom signature and, while it applies, the “Sent via Inkbox” footer — see Branding footer under Send message.
Fetching marks inbound mail read. AGEThere with an API key marks an unread inbound message read —is_readcomes backtruein the same response. Human (Console) reads don’t, and neither do the list, thread, or attachment routes, so an agent that only reads through those still needs the flags PATCH to mark read. This is distinct fromfirst_opened_at, which reflects the recipient opening a message you sent (see Open tracking).
Path parameters
Response (200)
JSON
Code examples
Send message
in_reply_to_message_id.
Path parameters
Request body
Provide at least one address across
recipients.to, recipients.cc, and recipients.bcc. A message can have at most 50 distinct recipients across these lists; repeated addresses count once, ignoring case.
The complete MIME message, including headers, body, attachments, and encoding overhead, must not exceed 10 MiB (10,485,760 bytes). Base64 encoding increases attachment size, so an attachment below the 25 MiB decoded-attachment cap can still exceed the message limit.
AttachmentUpload object:
Request example
JSON
Response (201)
Returns the created message metadata (same as a list item — body content is not included).Custom signatures
When enabled and available for the sending mailbox, a custom signature is added to sends, replies, reply-all, and forwards. Configure it through Update mailbox, not in each message request. The stored message includes the applied signature. An HTML signature adds a formatted HTML version to a text-only message while retaining the plain-text fallback. This does not enable open tracking. A text-only signature does not create an HTML version; an existing HTML body keeps its formatting. Original messages forwarded as attachments are unchanged. If the Inkbox branding footer also applies, it appears after the custom signature.Idempotency
Send, reply-all, and forward accept an optionalIdempotency-Key header of up to 255 characters. Omit it and every call is an independent send.
Supply it and the key is bound to the email before it is handed off for delivery, so retrying after a lost or timed-out response cannot put a second copy of the email on the wire.
This is at-most-once protection, not a replay. A repeat under a key that already sent returns an error rather than the original 201:
A
409 means the email went out. Fetch it with GET /messages?direction=outbound. A 503 means Inkbox cannot confirm what happened to the earlier attempt, so it will not send again under that key; check your outbound messages to see whether one exists. A 503 keeps returning while the outcome stays unresolved, which is deliberate — resolve it by looking the message up, not by forcing a send.
- Keys are scoped to your organization and to the endpoint. One key used for a send and for a forward does not collide.
- A retry does not spend quota twice. It reuses the original attempt’s recipient allowance rather than consuming it again.
- A key is remembered for 7 days, after which it can be used again.
- The request body is not part of the key. Reusing a key with different content is refused as an already-accepted send, not delivered. Use a fresh key for each distinct email.
- Retry with the same key. Never mint a new one for the same email. A new key is a new send, so if the first attempt did reach delivery, retrying under a fresh key is what puts the second copy on the wire. Errors raised before the send is accepted — validation, policy, storage and rate limits — leave the key unused, so retrying with it behaves like a first attempt.
Idempotency-Key, then send it. A lost response there can be retried and returns the original message.
Branding footer
By default, outbound mail carries a short “Sent via Inkbox” footer, appended to the text and HTML parts of every send, reply-all, and forward. Organizations on a paid plan can remove it — see Branding footer. While it applies, the footer is written into the stored message, so it changes what the API gives back: a laterGET /messages/{message_id} returns body_text and body_html with the footer appended — not the exact bytes you submitted. A send with no body at all comes back with a body containing only the footer. Snippets and search text are computed from the body you submitted, so snippet and search are unaffected.
Open tracking
Settrack_opens on a send or forward to embed an invisible tracking pixel in the HTML body. When the recipient’s mail client loads it, the message reports two fields (present on every message response):
track_opens requires an HTML part — a plain-text-only send returns 422. Tracking is per-message (“at least one observed open”), not per-recipient, and the pixel can raise spam scores, so a borderline message may be more likely to be filtered. first_opened_at (the recipient loaded the pixel) is distinct from is_read (your agent consumed the message via the API — see Get message).
Error responses
Mail limits are shared by every mailbox in the organization and count distinct envelope recipients, not messages. The default fixed-window ceilings are 50 recipients per 10 minutes, 80 per hour, and 100 per 24 hours; plan limits may be higher. An address repeated across To, Cc, or Bcc counts once.
A retryable limit response uses structured detail:
403 with detail.error set to mail_rate_limit_exceeded, along with limit, window_seconds, and recipient_count, and omits Retry-After.
Other send controls use distinct detail.error values:
Use the error code rather than the status alone to choose remediation. A
429
with Retry-After is retryable after the stated delay; a 403 requires a change
to the request, recipient relationship, sending mailbox, or plan.
Code examples
Reply to everyone
POST /messages.
Path parameters
Request body
Recipient resolution
- Inbound original —
Tois the originalReply-Toif present, otherwise the original sender.Ccis the originalTo+Cc. - Outbound original —
ToandCcreuse the originalToandCc. - In both cases the replying mailbox, duplicates, and the original BCC recipients are removed.
GET .../messages/{message_id}) returns the resolved reply_all_recipients ({ to, cc }) so UIs can prefill editable fields.
Request example
JSON
Response (201)
Returns aMessageResponse — the brand-new message representing the reply (same shape as a list item; body content is not included).
Accepts an optional Idempotency-Key header, under its own key namespace — see Idempotency.
Error responses
Code examples
Forward message
POST /messages and fire a message.forwarded webhook event on success (not message.sent).
Path parameters
Request body
At least one address is required across
recipients.to, recipients.cc, and recipients.bcc. The combined limit is 50 distinct recipients, ignoring case.
Modes
inline(default): Renders the original body below a preamble containing itsFrom:,Date:,Subject:,To:, andCc:headers. Original attachments appear as direct attachments to the forward. Inlinecid:images may break, and complex multipart structure is flattened.wrapped: Attaches the original message as a singlemessage/rfc822part, preserving its headers, body parts, attachments, and nested structure. Recipients may see it inline or as aforwarded.emlattachment, depending on their mail client. Use this for originals with inline images, calendar invites, or complex multipart content. The result preserves the message’s meaning and structure but may change its byte representation. DKIM-preserving forwarding is not supported.
Forwarding behaviour
- Original-attachment bytes are excluded from the 25 MiB cap on additional attachments. The complete MIME message, including the original content and encoding overhead, must fit within 10 MiB.
- The forward gets a brand-new
Message-ID. The original is referenced via anX-Forwarded-Message-Idheader. - Filename collisions across original attachments and caller
additional_attachmentsare deduplicated automatically (caller wins; originals get aforwarded-prefix and a numeric suffix).
Request example
JSON
Response (201)
Returns aMessageResponse — the brand-new message representing the forward (same shape as a list item; body content is not included).
Accepts an optional Idempotency-Key header, under its own key namespace — see Idempotency.
Error responses
Code examples
Update message flags
is_read or is_starred on a message. Omit a field to leave it unchanged.
This is how to mark mail read in bulk, to mark a message unread, or to mark read when you process from the list or thread routes (which never mark read on their own). Fetching a single inbound message with an API key marks it read automatically — see Get message.
Path parameters
Request body
Code examples
Delete message
204 No Content on success.
Deleting a message frees its storage immediately — the message and its associated storage overhead stop counting toward the inbox’s storage cap right away.
Path parameters
Code examples
Download attachment
302 redirect to a temporary download URL. Set redirect=false to get the URL as JSON instead.
Path parameters
Query parameters
Response (302) — redirect mode (default)
Redirects to a temporary download URL with aContent-Disposition: attachment header. The URL is valid for 15 minutes.
Response (200) — JSON mode
JSON
Error responses
Code examples
Message object
MessageResponse (list items)
MessageDetailResponse (single message)
Includes allMessageResponse fields plus:

