Retrieve a stored message

GET/api/v1/domains/{domain}/messages/{messageId}
Requires anorganization API keywith the scopeevents:read

The archived copy of a message, which is what a webhook's storage.url points at.

messageId is the id exactly as it arrived, angle brackets included. Stripping them returns 404: the archive stores the id as it was received, and a bridge that helpfully removed < and > is why every inbound message 404'd here until 2026-09-14.

Parameters

NameInTypeDescription
domainrequiredpathstringThe domain id, or the domain name itself.
messageIdrequiredpathstringThe message id exactly as it arrived, angle brackets included.

Request

GET/api/v1/domains/{domain}/messages/{messageId}
curl -X GET 'https://app.mailyte.com/api/v1/domains/yourdomain.com/messages/01JBT8XQ2M9WYC3K4F6R7S8T9V' \
  -H 'Authorization: Bearer mk_live_YOUR_API_KEY'
The key names its own organization, so no X-Organization-ID header is needed.

Response

Success.

  • dataobject
    • objectstringarchived_message | archived_message_preview

      Which of the two shapes you got. `archived_message` is the default and carries `raw`; `archived_message_preview` is `?format=html` and carries the parsed fields instead. Branch on this, never on the presence of a key.

    • message_idstring

      The RFC 5322 Message-ID, angle brackets included -- the same string a send returned and every event publishes. This endpoint's path parameter is this value, percent-encoded; the archive stores the id exactly as it arrived, which is why the brackets are kept everywhere rather than stripped for tidiness. NULL MEANS UNKNOWN -- the stored copy came back without an id we could state in full -- and never that the message had no Message-ID, because you just looked it up BY its Message-ID. The value you put in the path is the authoritative one; a null here is us failing to echo it, not a property of the message.

    • domainstring

      The domain this copy is archived under. NULL MEANS UNKNOWN: the archiver returned the record without one. It is not a message that belongs to no domain -- as with `message_id`, you named the domain in the path to get here, and that value is the one to trust.

    • archived_atstring

      Null means we could not read a date off the stored copy, not that it was archived at the epoch.

    • legal_holdboolean

      Default shape only. True means retention cannot expire this copy.

    • rawstring

      Default shape only. The `message/rfc822` bytes exactly as stored -- headers, body, MIME parts. Unsanitised: do not render it in a browser, use `?format=html` for that. NULL MEANS UNKNOWN AND IS A PROBLEM, not an empty message: the archive returned a record for this id but no bytes with it, so the copy is catalogued and its content is not readable here. There is no such thing as an archived message of zero bytes, so do not treat null as one -- retry, or fall back to `?format=raw`. On the `archived_message_preview` shape this key is ABSENT rather than null, deliberately: see `object`.

    • headersobject

      `?format=html` only. The parsed headers, name to value.

    • htmlstring

      `?format=html` only. The body DE-FANGED for display: remote resources stripped, scripts removed. The preview deliberately ships no raw copy beside it, because a payload bound for a browser one field away from the unsanitised bytes is one mistake from rendering the wrong one. NULL MEANS NONE: the message carried no HTML part -- a plain-text-only message is the ordinary case -- so render `text` instead. It does not mean de-fanging removed everything; a body stripped down to nothing still comes back as markup, not as null.

    • textstring

      `?format=html` only. The plain-text fallback. NULL MEANS NONE: the message carried no `text/plain` part, which is what an HTML-only message looks like. `html` and `text` can BOTH be null on the same message -- one with only attachments, or one the parser could make nothing of -- and that is the case to check for before rendering a preview, because there is nothing to show.

    • attachmentsarray<object>

      `?format=html` only. The attachment manifest -- names, types and sizes, not the bytes.

    • blocked_remote_countinteger

      `?format=html` only. How many remote images or resources were blocked while de-fanging, so a caller can say so rather than showing a silently broken layout.

Returned inside the standard envelope.

Errors

StatusWhen
401The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist.
403The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys.
404No such resource in this organization.
422The request was understood but the values were not acceptable.
429Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait.

Every status, with what causes it and what to do, is on the error reference.