Skip to content

Blog · Published 2026-10-21 · AgentiSend team

Mail an agent reads is where it gets hurt

Mail an agent reads on AgentiSend carries inbound_verdict. The label is clear, review, or unavailable, and the body stays data.

Filed under Guardrails

Mail an agent reads on AgentiSend carries inbound_verdict. The label is clear, review, or unavailable, and the body stays data.

A send the agent writes is checked before it leaves. A message a stranger wrote is not. The text arrives whole, and the next step is often to hand that text to a model as if it were a note from the person who runs the agent. The model cannot see which sentences the operator typed and which sentences arrived from the outside.

What the label is for

An agent that answers customers has to read the reply. The reply is still untrusted input. It can ask the model to ignore its instructions, to forward the thread, to reveal a key, or to treat a hidden line as a new order. A short message under a normal subject is enough, because the model is already trying to be helpful with whatever it was given.

A budget caps how many messages the key may send. A loop guard holds a repeated send. Neither one reads the message that just arrived. inbound_verdict is that read. Hold mode is the choice to keep a review message away from the arrival webhook until a person releases it.

What the verdict checks

Every received message carries the object. clear is ordinary mail. review means the message asks an assistant to ignore its instructions, tries to give an assistant a new role, addresses an assistant as an AI, mentions a system prompt, tells an assistant to hide something from the person, asks for the mail to be forwarded, asks for a key or a password, hides text, carries a long encoded block, uses markup that marks a system role, or asks for an action from a Reply-To address that is not the From address. unavailable means the message is a bounce, has no text, or is larger than 256 KB, so it was not judged.

GET /emails/receiving/{id} returns the verdict with reasons. The list and the thread list carry verdict on each row. email.received carries the same object. The reasons are sentences a person can check. They are not a score, and they are not a command to the model.

A message the checks do not match stays clear, including a question, a thank-you, or a thread that quotes an earlier reply. A person can read the reasons and release a message that was held for a phrase that was harmless in context. A clear label means those checks did not match. It does not mean the text is trusted. A novel wording can still be hostile.

Hold mode

A domain is in one of two modes, set with PATCH /domains/{id} and inbound_hold_mode.

Monitor is the default. The message is stored and email.received fires with the label. The label does not, by itself, keep the text away from the model. If the agent reads every arrival, a review message still reaches it. Read verdict before you put the body in front of the model, and pass the body as quoted data with the reasons beside it.

Hold is the other mode. A review message is stored with held true. email.received waits. email.received.held fires instead. The message appears in GET /agent-actions with kind inbound_release and in GET /emails/receiving?held=true. Inbox reads over MCP leave held messages out unless include_held is true. GET /emails/receiving/{id} still returns a held message to the account that owns it, so a person can read it before deciding.

POST /emails/receiving/{id}/release takes a reason. email.received fires once. A second release does not send it again. Releasing is a person's decision. The key the model holds should not be the caller that releases its own input. In hold mode, wait for email.received, which fires after the release.

The body is data

The verdict is a label. The body is still data. Nothing in either one is followed.

extracted_text removes quoted history, a signature, and a few trailing lines so the new reply is easier to read. It does not make the remainder safe. A sentence that survived extraction is still a sentence a stranger wrote. Put it in the tool result, or in the user turn, and keep the model's own instructions where your framework puts the operator's. Do not paste the body into the system prompt. Do not treat a line that says it is a system message as one.

The model should not be told that clear means trusted, or that review is proof of an attack. Both are inputs. Hold mode decides whether a review message waits for a person before the arrival webhook fires.