mail_read
Gate: ungated · no kind, zero authority · read
Fetches one message and flattens it to what a language model can use: the header plus the text/plain body, with transfer encoding and charset already decoded. Ungated for the same reason the listing is — reading is context, never authority. The defence against what a mail says is the gate on every action the assistant takes afterwards, not a prompt in front of the reading.
Input
| Field | Type | Required | Notes |
|---|---|---|---|
uid | integer | yes | The message UID, as returned by mail_list or mail_search. |
folder | string | no | Folder the message is in; defaults to INBOX. |
Output
A JSON object with uid, from, to, subject, date and body. The body is capped at 16 KiB — for the whole message, not per part, and enforced while reading rather than by cutting a finished string — and truncation is marked. Several plain-text parts are separated by a blank line instead of running into one another. A message with no plain-text part comes back with an empty body rather than a page of markup, and attachments are not carried at all.
From JavaScript
const mail = nocturn.call("mail_read", { uid: 4711 });Notes
The fetch uses BODY.PEEK[], so reading through the assistant never marks a message as seen. A UID the server no longer has is an ordinary not-found error — a message moved or deleted between a listing and a read is normal, not exceptional. Mail is foreign text: everything it contains is written by whoever sent it, which makes it the plainest prompt-injection channel in the tree. Vault values echoed back inside a message are redacted before the model sees them.