How to stop an AI agent from emailing the wrong people
· By the Shotoku team
Short answer:check every recipient in code before the message is sent. Allow domains you trust, and hold everything else for a human. An email can’t be unsent, so this check has to run before the send, not in a review afterward.
Why does an agent email the wrong person?
- Bad context. The agent picks a similar name or an old address from its notes.
- Instructions hidden in content. A message it reads can tell it to forward something elsewhere.
- Scope creep. Asked to draft a reply, it sends one.
A rule in the prompt helps with none of these reliably. The second case is worse: the model is following instructions, just the wrong ones.
How do you check recipients?
Install Shotoku:
Write a policy keyed on the recipient’s domain:
Then wrap your send function. Check each domain, and send only if all of them pass, so one outside address in the list holds the whole message:
Include CC and BCC in to, or the check won’t see those recipients.
What happens when it runs?
We ran this logic on the current npm release of @shotoku/core:
| Recipients | Result |
|---|---|
| a@yourcompany.com and b@eu.yourcompany.com | sent |
| a@yourcompany.com and c@customer.com | held: customer.com needs a human |
| Same list, after shotoku approve | sent |
| Same list again | held again |
What should you watch out for?
- An approval covers the next email to that domain, not one message. The check above knows the domain, not the content. To tie an approval to one message, pass a hash of it as
fingerprintin the request. - Domains aren’t people. Approving
gmail.comapproves everyone there. Use a specific rule only for domains you control or fully trust. - Domain rules can’t judge content. An allowed internal address can still receive the wrong attachment. This limits who gets mail, not what it says.
What about a Gmail MCP server?
Wrapping an MCP serveralso works, with one difference: a wrapped rule matches the tool name, not the recipient. So you can allow drafts, and hold every send for a human, but you can’t allow one domain through that route.
| Route | Can the agent skip it? | Rule matches on |
|---|---|---|
| authorize() in your send function | Not if it's the only way to send | Recipient domain |
| Wrapped MCP mail server | Not through MCP | Tool name |
Common questions
Should agents send email without review at all?
Internal notifications to known addresses are usually fine. For anything that reaches a customer, start with human approval, then relax it once your history shows the agent gets it right.
Does the email text leave my machine?
Not through Shotoku. It runs locally and this check sends it only the domain, which is stored in a local file.
Shotoku is built for spend controls, and the same policy engine covers email. See the policy reference.