Messages
A message is one email received by one of your inboxes. You can list and search an inbox's messages, read a message with its parsed bodies and authentication results, render its HTML safely, download attachments or the raw source, export a whole inbox, and delete messages.
Message endpoints accept a session token or an API key. A message in an inbox you do not own returns 404. Messages are removed when they are older than the inbox's retention_secs, or when the inbox expires.
The message model
The list endpoints return a short form. GET /v1/messages/:id returns the full form, which adds the bodies and parts.
List fields
- Name
id- Type
- string
- Description
Message id.
- Name
inbox_id- Type
- string
- Description
The inbox that received it.
- Name
received_at- Type
- timestamp
- Description
When it was received.
- Name
from_addr- Type
- string | null
- Description
Sender address from the
Fromheader.
- Name
from_name- Type
- string | null
- Description
Sender display name.
- Name
subject- Type
- string | null
- Description
Subject.
- Name
snippet- Type
- string | null
- Description
Short text preview.
- Name
size_bytes- Type
- integer
- Description
Size of the raw message.
- Name
has_attachments- Type
- boolean
- Description
Whether the message has attachments.
- Name
read_at- Type
- timestamp | null
- Description
When it was marked read.
Full message, additional fields
- Name
to_addrs- Type
- array
- Description
Recipient addresses.
- Name
auth_results- Type
- object | null
- Description
SPF, DKIM and DMARC results computed when the message arrived. See below.
- Name
text_plain- Type
- string | null
- Description
Plain-text body.
- Name
html_sanitized- Type
- string | null
- Description
HTML body after sanitising. Inline images still use
cid:references here; use the HTML view to render it with images.
- Name
parts- Type
- array
- Description
MIME parts. Each has
index(used in the download URL),content_type,filename,content_id,size_bytesandis_inline.
Subjects, names, snippets and filenames come from the sender. Display them as text, never as HTML.
Authentication results
- Name
spf- Type
- object | null
- Description
resultanddomain(theMAIL FROMdomain, or the HELO name for an empty sender).
- Name
dkim- Type
- array
- Description
One entry per DKIM signature:
result,domain(d=) andselector(s=).
- Name
dmarc- Type
- object | null
- Description
result,domain(theFromdomain) andpolicy(none,quarantine,reject, ornull).
- Name
verified- Type
- boolean
- Description
Whether verification ran at all.
result uses the RFC 8601 verdict names: pass, fail, softfail, neutral, temperror, permerror, none.
List messages
Returns a page of the inbox's messages, newest first. See pagination. Listing an inbox counts as activity and pushes its expiry forward.
Optional query parameters
- Name
limit- Type
- integer
- Description
Page size, 1–100. Default 25.
- Name
cursor- Type
- string
- Description
next_cursorfrom the previous page.
Request
curl -G https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b/messages \
-H "Authorization: Bearer {token}" \
-d limit=25
Response
{
"items": [
{
"id": "019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d",
"inbox_id": "019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b",
"received_at": "2026-10-26T08:05:12Z",
"from_addr": "noreply@example.com",
"from_name": "Example",
"subject": "Your sign-in code",
"snippet": "Your code is 481920. It expires in 10 minutes.",
"size_bytes": 5821,
"has_attachments": false,
"read_at": null
}
],
"next_cursor": null
}
Search messages
Full-text search over subject, snippet, sender address (whole, local part or domain) and sender name. The query uses web-search syntax: "exact phrase", -excluded, or. Results are best matches first, at most 100, with no cursor (next_cursor is always null).
Accounts only: anonymous sessions get 403 tier_required. Rate limited per tier (10 per minute for a free account).
Required query parameters
- Name
q- Type
- string
- Description
Search terms, 1–200 characters.
Optional query parameters
- Name
limit- Type
- integer
- Description
Result cap, 1–100. Default 25.
Request
curl -G https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b/messages/search \
-H "Authorization: Bearer {token}" \
--data-urlencode 'q="sign-in code" -newsletter'
Get a message
Returns the full message: list fields, recipients, authentication results, bodies and parts.
Request
curl https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d \
-H "Authorization: Bearer {token}"
Response
{
"id": "019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d",
"inbox_id": "019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b",
"received_at": "2026-10-26T08:05:12Z",
"from_addr": "noreply@example.com",
"from_name": "Example",
"subject": "Your sign-in code",
"snippet": "Your code is 481920. It expires in 10 minutes.",
"size_bytes": 5821,
"has_attachments": false,
"read_at": null,
"to_addrs": ["alice@nullnet.sh"],
"auth_results": {
"spf": { "result": "pass", "domain": "example.com" },
"dkim": [
{ "result": "pass", "domain": "example.com", "selector": "s1" }
],
"dmarc": { "result": "pass", "domain": "example.com", "policy": "reject" },
"verified": true
},
"text_plain": "Your code is 481920. It expires in 10 minutes.\n",
"html_sanitized": "<p>Your code is <b>481920</b>.</p><img src=\"cid:logo@example.com\">",
"parts": [
{
"index": 2,
"content_type": "image/png",
"filename": "logo.png",
"content_id": "logo@example.com",
"size_bytes": 2048,
"is_inline": true
}
]
}
Get the HTML view
Returns a complete HTML page with the sanitised body, ready for a sandboxed iframe. A message without HTML is rendered as preformatted plain text.
Inline (cid:) images are resolved when the page is served. Images up to 32 KiB are embedded as data: URIs. Larger ones become signed part URLs, valid for 10 minutes, that load without a token. References that match no image part are left as cid:.
The page is served with this Content Security Policy, which blocks scripts, forms and all network access except same-origin and data: images:
default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'; form-action 'none'; base-uri 'none'; sandbox
It also sets X-Content-Type-Options: nosniff and Referrer-Policy: no-referrer. An iframe src cannot carry the token, so fetch the page with your token and set it as the srcdoc of an iframe with an empty sandbox attribute (no allow-*). Do not insert html_sanitized into your own page. Signed image URLs expire, so fetch the view again rather than caching it.
Request
curl https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d/html \
-H "Authorization: Bearer {token}"
Download a part
Downloads one MIME part by its index. Rate limited per tier (attachment downloads per hour).
Only images whose bytes match their type (PNG, JPEG, GIF, WebP) are served inline with their content type. Everything else is served as application/octet-stream with Content-Disposition: attachment. Responses carry X-Content-Type-Options: nosniff.
Optional query parameters
- Name
exp- Type
- integer
- Description
Expiry of a signed URL, Unix seconds.
- Name
sig- Type
- string
- Description
Signature of a signed URL. With
exp, replaces the token. Signed URLs are created by the HTML view and work for image parts only.
Request
curl -OJ https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d/parts/2 \
-H "Authorization: Bearer {token}"
Download the raw message
Downloads the original message bytes as received (RFC 5322), as message/rfc822 with an attachment disposition and a <id>.eml file name. Counts against the raw-download budget per hour.
Request
curl -o message.eml https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d/raw \
-H "Authorization: Bearer {token}"
Export an inbox
Streams every live message of the inbox as one mboxrd file (application/mbox, file name <inbox id>.mbox). Line endings are converted to LF, and lines starting with From (after any >) are quoted with >. Counts as one raw download.
Request
curl -o inbox.mbox https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b/export \
-H "Authorization: Bearer {token}"
Mark as read
Sets read_at. Returns 204.
Request
curl -X POST https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d/read \
-H "Authorization: Bearer {token}"
Delete a message
Deletes the message and updates the inbox counters. Other clients watching the inbox over the WebSocket receive a message_deleted event. Returns 204.
Request
curl -X DELETE https://mail.nullnet.sh/v1/messages/019a2f61-3e5a-7b12-8c4d-6e8f0a2b4c6d \
-H "Authorization: Bearer {token}"