Skip to content
Inkbox

Inkbox

DocsPricingBlogContact
GuidesAPI ReferenceChangelog

Ctrl K

GuidesAPI ReferenceChangelog

Jump to

Messages

Messages represent individual emails in a mailbox. List and detail endpoints return message metadata; full body content (text/HTML) is fetched from storage on detail requests. All list endpoints use cursor-based pagination.


List messages GET

GET /mailboxes/{email_address}/messages

List messages in a mailbox, newest first, with cursor pagination.

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the mailbox

Query parameters

ParameterTypeDefaultDescription
cursorstringOpaque cursor from a previous response's next_cursor
limitinteger50Results per page (1–100)
directionstringFilter by "inbound" or "outbound". Omit for all messages
start_datetimestringOnly messages created on or after this date/time
end_datetimestringOnly messages created on or before this date/time; a bare date includes the whole day
tzstringUTCIANA zone for interpreting zone-less start_datetime/end_datetime values. Defaults to UTC

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)

JSONJSON

Code examples


Get message GET

GET /mailboxes/{email_address}/messages/{message_id}

Get a single message with its full body content (plain text and HTML).

The body returned is the body Inkbox stored, which is not always the body the caller submitted: while the branding footer applies, outbound body_text/body_html come back with the "Sent via Inkbox" footer appended — see Branding footer under Send message.

Fetching marks inbound mail read. A GET here with an API key marks an unread inbound message read — is_read comes back true in 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 from first_opened_at, which reflects the recipient opening a message you sent (see Open tracking).

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the mailbox
message_idUUIDUnique identifier of the message

Response (200)

JSONJSON

Code examples


Send message POST

POST /mailboxes/{email_address}/messages

Compose and send an email from a mailbox. Threading is automatically resolved from in_reply_to_message_id.

Storage limits

Every inbox has a storage cap set by your plan. A send that would push the inbox above its cap is refused with a 402 — from this endpoint, reply-all, and forward alike — until space is freed (delete messages or threads) or the plan is upgraded. See pricing for per-plan caps.

Receiving is never blocked. Inbound mail is always accepted, and still counts toward the inbox's usage. Current usage and the cap are on the mailbox object as storage_used_bytes and storage_limit_bytes.

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the sending mailbox

Request body

FieldTypeRequiredDescription
recipients.tostring[]YesPrimary recipients (at least one)
recipients.ccstring[]NoCC recipients
recipients.bccstring[]NoBCC recipients (excluded from headers, delivered separately)
subjectstringYesEmail subject line (max 998 chars)
body_textstringNoPlain-text body
body_htmlstringNoHTML body
in_reply_to_message_idstringNoRFC 5322 Message-ID of the email being replied to
reply_tostringNoOptional Reply-To address. If set, recipients' mail clients route replies here instead of the sending mailbox.
attachmentsobject[]NoFile attachments (see below). Max total 25 MB. Some file types are rejected; the API returns a 400 with a descriptive error if one is blocked.
track_opensbooleanNoEmbed an open-tracking pixel in the HTML body. Requires body_html — a plain-text-only send with track_opens returns 422. Default false. See Open tracking.

AttachmentUpload object:

FieldTypeDescription
filenamestringFile name (max 255 chars)
content_typestringMIME type (e.g. application/pdf)
content_base64stringBase64-encoded file content

Request example

JSONJSON

Response (201)

Returns the created message metadata (same as a list item — body content is not included).

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 later GET /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

Set track_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):

FieldTypeDescription
first_opened_atstring | nullISO 8601 time of the first observed open, or null if none seen yet. This is the reliable signal.
open_countintegerObserved opens (default 0). Approximate, not an exact tally: image proxies such as Apple Mail Privacy Protection and Gmail preload the pixel and inflate it, while rapid repeat opens are collapsed into one and can deflate it.

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

StatusDescription
402Sending the message would exceed the inbox storage limit — delete messages or upgrade the plan
429Mailbox has exceeded 600 sends in the last hour. Response includes Retry-After (seconds), X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers

Code examples


Reply to everyone POST

POST /mailboxes/{email_address}/messages/{message_id}/reply-all

Reply to every visible participant on a stored message. Recipients are resolved server-side from the original — you don't pass them. The reply stays in the original thread and counts against the same send rate limits as POST /messages.

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the replying mailbox
message_idUUIDUUID of the message being replied to

Request body

FieldTypeRequiredDescription
subjectstringNoOverride; defaults to "Re: " + original.subject (idempotent — won't double-prefix). Max 998 chars.
body_textstringNoPlain-text reply body.
body_htmlstringNoHTML reply body.
attachmentsobject[]NoBase64-encoded attachments. Same AttachmentUpload shape and limits as Send.
reply_tostringNoOptional Reply-To header on the reply.

Recipient resolution

  • Inbound originalTo is the original Reply-To if present, otherwise the original sender. Cc is the original To + Cc.
  • Outbound originalTo and Cc reuse the original To and Cc.
  • In both cases the replying mailbox, duplicates, and the original BCC recipients are removed.

The message detail (GET .../messages/{message_id}) returns the resolved reply_all_recipients ({ to, cc }) so UIs can prefill editable fields.

Request example

JSONJSON

Response (201)

Returns a MessageResponse — the brand-new message representing the reply (same shape as a list item; body content is not included).

Error responses

StatusDescription
400Attachment blocked/oversize
402Sending the message would exceed the inbox storage limit — delete messages or upgrade the plan
403Organization mismatch, contact-rule block, or unclaimed-agent recipient restriction
404Mailbox or original message not found
422No reply-all recipients could be resolved, or the message was rejected at send time
429Send rate limit exceeded (same quota as POST /messages)

Code examples


Forward message POST

POST /mailboxes/{email_address}/messages/{message_id}/forward

Forward a previously stored message out from this mailbox. A forward intentionally creates a new thread — it does not chain into the original conversation, matching the default behavior of Gmail, Outlook, and Apple Mail.

Forwards count against the same send rate limits as POST /messages and fire a message.forwarded webhook event on success (not message.sent).

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the forwarding mailbox
message_idUUIDUUID of the original message to forward

Request body

FieldTypeRequiredDescription
recipients.tostring[]Primary recipients
recipients.ccstring[]CC recipients
recipients.bccstring[]BCC recipients (excluded from headers, delivered separately)
modestringNo"inline" (default) or "wrapped". See Modes below.
subjectstringNoOverride; defaults to "Fwd: " + original.subject (idempotent — won't double-prefix if the original already starts with Fwd: / Fw:). An empty or missing original subject becomes "Fwd: (no subject)". Max 998 chars.
body_textstringNoPlain-text caller note prepended above the original body (inline) or included as a top-level note (wrapped).
body_htmlstringNoHTML caller note.
additional_attachmentsobject[]NoCaller-authored attachments that ride alongside the forwarded content. Same AttachmentUpload shape, rejection behaviour, and 25 MB caller cap as Send.
include_original_attachmentsbooleanNoinline mode only. Default true — original attachments are re-attached as direct outbound parts. Ignored in wrapped mode (originals live inside the wrapped .eml).
reply_tostringNoOptional Reply-To header on the forward's outer envelope. The original's Reply-To (if any) is preserved inside the wrapped MIME but is not auto-inherited.
track_opensbooleanNoEmbed an open-tracking pixel; requires an HTML part on the outgoing forward. Inline mode inherits the original's HTML; wrapped mode needs a body_html. A no-HTML forward returns 422. Default false. See Open tracking.

At least one address is required across recipients.to, recipients.cc, and recipients.bcc.

Modes

  • inline (default) — Renders the original body inline below a Gmail-style preamble that includes From:, Date:, Subject:, To:, and Cc: from the original. Original attachments are re-attached as direct outbound parts. Lossy: inline cid: images may break, and non-trivial multipart structure is flattened.
  • wrapped — Attaches the original raw MIME as a single message/rfc822 part, semantically preserving all headers, body parts, attachments, and nested structure. Recipient clients either expand it inline (Gmail) or show it as a forwarded.eml attachment (Outlook). Use this for originals with inline images, calendar invites, or complex multipart. The result is semantically equivalent to the original, not byte-for-byte equivalent; DKIM-preserving forwarding is not supported in v1.

Forwarding behaviour

  • Attachment type rejection applies only to caller-authored attachments, not to content carried over from the original message.
  • Original-attachment bytes are not counted against the 25 MB caller cap. Only the 10 MB outbound limit on the final composed MIME applies to the combined output.
  • The forward gets a brand-new Message-ID. The original is referenced via an X-Forwarded-Message-Id header.
  • Filename collisions across original attachments and caller additional_attachments are deduplicated automatically (caller wins; originals get a forwarded- prefix and a numeric suffix).

Request example

JSONJSON

Response (201)

Returns a MessageResponse — the brand-new message representing the forward (same shape as a list item; body content is not included).

Error responses

StatusDescription
400Caller attachment blocked/oversize, or final composed MIME exceeds the 10 MB outbound limit
402Sending the message would exceed the inbox storage limit — delete messages or upgrade the plan
403Organization mismatch, contact-rule block, or unclaimed-agent recipient restriction
404Mailbox or original message not found
422Original message cannot be forwarded — raw content was not retained (applies only to historical inbound messages ingested before raw-MIME retention was enabled)
429Send rate limit exceeded (same quota as POST /messages)
502Failed to load original body or attachments from storage

Code examples


Update message flags PATCH

PATCH /mailboxes/{email_address}/messages/{message_id}

Update 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

ParameterTypeDescription
email_addressstringEmail address of the mailbox
message_idUUIDUnique identifier of the message

Request body

FieldTypeRequiredDescription
is_readbooleanNoMark as read (true) or unread (false)
is_starredbooleanNoStar or unstar the message

Code examples


Delete message DELETE

DELETE /mailboxes/{email_address}/messages/{message_id}

Delete a message. Returns 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

ParameterTypeDescription
email_addressstringEmail address of the mailbox
message_idUUIDUnique identifier of the message

Code examples


Download attachment GET

GET /mailboxes/{email_address}/messages/{message_id}/attachments/{filename}

Download an attachment from a message. By default, responds with a 302 redirect to a temporary download URL. Set redirect=false to get the URL as JSON instead.

Path parameters

ParameterTypeDescription
email_addressstringEmail address of the mailbox
message_idUUIDUnique identifier of the message
filenamestringAttachment filename (must match exactly with attachment_metadata[].filename)

Query parameters

ParameterTypeDefaultDescription
redirectbooleantruetrue returns a 302 redirect to the download URL. false returns the URL as JSON.

Response (302) — redirect mode (default)

Redirects to a temporary download URL with a Content-Disposition: attachment header. The URL is valid for 15 minutes.

Response (200) — JSON mode

JSONJSON
FieldTypeDescription
urlstringTemporary download URL (valid for 15 minutes)
filenamestringAttachment filename
expires_inintegerURL expiration time in seconds

Error responses

StatusDescription
403Mailbox does not belong to your organization
404Mailbox, message, or attachment not found

Code examples


Message object

MessageResponse (list items)

FieldTypeDescription
idUUIDUnique message identifier
mailbox_idUUIDOwning mailbox
thread_idUUID | nullConversation thread, if resolved
message_idstringRFC 5322 Message-ID header value
from_addressstringSender address
to_addressesstring[]Primary recipients
cc_addressesstring[] | nullCC recipients
subjectstring | nullEmail subject line
snippetstring | nullFirst ~200 chars of the plain-text body
directionstringinbound or outbound
statusstringqueued, sent, delivered, bounced, failed, or received
is_readbooleanWhether the message has been read
is_starredbooleanWhether the message is starred
has_attachmentsbooleanWhether the message has attachments
reply_tostring | nullReply-To header (inbound: parsed from the original; outbound: caller-supplied override)
created_atstringCreation timestamp (ISO 8601)

MessageDetailResponse (single message)

Includes all MessageResponse fields plus:

FieldTypeDescription
body_textstring | nullPlain-text body
body_htmlstring | nullHTML body
bcc_addressesstring[] | nullBCC recipients
in_reply_tostring | nullRFC 5322 In-Reply-To header
referencesstring[] | nullRFC 5322 References headers
attachment_metadataobject[] | nullAttachment descriptors for each file, including filename, content type, and size
ses_message_idstring | nullOutbound provider message ID
updated_atstringLast update timestamp (ISO 8601)
reply_all_recipientsobject | nullServer-suggested reply-all recipients ({ to, cc }), with the mailbox itself and BCC excluded — prefill editable To/Cc fields from this

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Y CombinatorBacked by Y Combinator
Messages