Trust layer · MachineMail Docs

Why email is an injection vector

An inbox is an open door. Anyone who knows the address can put text in front of your agent, and the agent reads that text with the same attention it gives your instructions. MachineMail checks every inbound message before it is stored and attaches a trust report that says who really sent it and whether anything in it is trying to manipulate the reader.

Why email is an injection vector

A human skims an email and ignores what looks wrong. A model reads every token, including tokens a human never sees:

The defence is the same one you use for any untrusted input: authenticate the source, strip what the reader can’t see, and decide what to do from a verdict instead of from the content.

What happens to every inbound message

Between parsing and storage, every inbound message goes through these checks:

  1. Authentication. SPF, DKIM and DMARC results are read from the receiving server’s headers, and the authenticated domain is checked for alignment with the From domain. See Authentication.

  2. Sender relationship. Has this inbox written to the sender before? Is the sender on your allow or block list? Is it a free mail provider?

  3. Content scrubbing. The body is split into body, quoted history, signature, disclaimer and hidden text. Hidden text and invisible characters are removed, tracking pixels are dropped, and HTML is sanitised. What is left is the agent-safe text. See Content scrubbing.

  4. Links and attachments. Every link is checked for mismatched text, lookalike domains, raw IPs, shorteners and brand impersonation. Every attachment gets a risk rating from its name, declared type and actual bytes. See Links and Attachments.

  5. Classification. Rules and a hosted model estimate the probability of spam, phishing, prompt injection, credential or payment requests, and urgency, and pick a category. See Classifier.

  6. Verdict. Everything is folded into a level (verified, known, unknown, suspicious, quarantined), a score from 0 to 1, and a list of plain-English reasons. See Trust report.

The raw message is never modified. The report is derived from it, computed once at ingest, and stored with the message.

If the trust layer fails on a message, the message is still delivered, without a trust field. Mail is never dropped because a check failed.

What the verdict changes

The level and classification also decide the message’s labels and the event it emits:

Outcome Labels Event
level is quarantined QUARANTINE replaces INBOX message.received.quarantined
classification.is_spam is 0.9 or higher SPAM replaces INBOX message.received.spam
DMARC failed, or both SPF and DKIM failed UNAUTHENTICATED is added (INBOX stays) message.received.unauthenticated
Sender not allowed by your receive lists BLOCKED instead of INBOX message.received.blocked
Anything else INBOX, UNREAD message.received

The rules are checked in that order and the first match wins, except that the receive-list check comes first of all. Message lists hide QUARANTINE, SPAM, BLOCKED, UNAUTHENTICATED and TRASH mail unless you ask for it with include_quarantine, include_spam and so on. See Webhook events for the payloads.

Where the report appears

The same report, in snake_case, is available everywhere you read mail:

Where What you get
GET /v0/inboxes/{inbox_id}/messages/{message_id} the full report as message.trust
GET /v0/inboxes/{inbox_id}/messages/{message_id}/trust the report on its own
Message lists (GET .../messages) trust_level on each item, for badges and filtering
Webhooks for message.received* events the full message, report included, in the payload
MCP get_message, get_thread, wait_for_message the agent-safe text plus a trust summary; quarantined content withheld
MCP get_trust_report the full report, with hidden text redacted
Dashboard inbox view a Trust panel and an Agent-safe / Raw toggle

Outbound messages have no trust report.

Read a message's trust report

curl https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/messages/msg_2Vb7.../trust \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

The rule of thumb

Give the model trust.content.text, never the raw text or html, and decide what the agent may do from trust.level:

Using trust in agents turns this into code and prompt templates.