Jean Galea

AI, Investing, Health, and Building Businesses

  • Start Here
  • AI & Tech
    • AI
    • Tech
    • Modern Web Stack
    • Business
  • Investing
    • Investing Basics
    • Crypto
    • Stocks
    • P2P Lending
    • Real Estate
    • Calculators
    • Dividends
    • FIRE & Early Retirement
    • European Investing Hub
  • Life
    • Essays
    • Barcelona
    • Padel
    • Health & Fitness
    • Hobbies
    • Family
  • About
    • My Story
    • Projects
    • AI Consultancy
    • Plugins
    • Speaking
  • Blog
  • Community
    • Good Life Collective
    • Daily Driver AI
  • Search

How to Stop an AI Agent From Approving Its Own Email

Published: October 31, 2026Leave a Comment

The mailbox-mcp approve command in a terminal, showing a queued email and the Type yes to send prompt

An AI lab director asked her agent to suggest emails to delete and wait for her OK. Her inbox was big enough that the agent compacted its context to keep going, and the summary dropped the instruction to wait. It deleted hundreds of emails, and it kept going when she tried to stop it from her phone.

The instruction was a sentence in a chat. Chats get summarized, truncated and overridden, so a rule that lives there is a request. For email, the fix is to make the approval a step the agent can’t perform, however long the session runs.

This tutorial sets that up with mailbox-mcp, the open-source email server my own agents work through. If you run agents unattended, as in my Claude Code overnight setup, this is the rule that matters most.

What You’ll End Up With

Every email the agent sends gets written to a queue instead of going out. The agent can draft, reply and forward all day, and each one waits as a file. You release a message by running one command in your own terminal, which prints the full message and asks you to type yes.

The agent can’t run that command successfully. It reads your answer from the terminal device itself (/dev/tty), and a shell started by an agent has no terminal to open.

Prerequisites

A current mailbox-mcp release, an MCP client such as Claude Code (the building blocks, if you’re new to it), and at least one account already connected. The README covers installing the server and adding Gmail, IMAP or JMAP accounts.

The server runs from npm, so the MCP entry looks like this:

{
  "mcpServers": {
    "mailbox": {
      "command": "npx",
      "args": ["-y", "mailbox-mcp"]
    }
  }
}

Turn On External Approval

Safety settings live per account in ~/.mailbox-mcp/accounts.json. Add "approval": "external" to the account your agent sends from:

{
  "accounts": {
    "work": {
      "provider": "gmail",
      "email": "[email protected]",
      "approval": "external"
    }
  }
}

Restart the server. There’s deliberately no tool for changing these settings from inside a session, so the agent can’t switch approval off. If an entry is malformed, the server refuses to start instead of running unguarded.

Watch a Send Get Queued

Ask the agent to email someone. Instead of sending, it reports that the message is waiting and gives you an id. send_email, reply_email, forward_email, send_draft and send_template all work this way.

Every send guard still runs before the message is queued: the recipient allowlist, the daily cap, the new-recipient confirmation. The queue holds the fully resolved message under ~/.mailbox-mcp/pending/.

Approve It From Your Terminal

Open a terminal yourself and work the queue:

mailbox-mcp pending        # id, account, from, recipients, subject, created
mailbox-mcp show <id>      # the full message
mailbox-mcp approve <id>   # prints it, asks "Type yes to send", sends exactly that
mailbox-mcp reject <id>    # drops it

If you run the server through npx, put npx in front of each command.

When you approve, the command does more than send:

  • It prints the whole message and reads your confirmation from /dev/tty, not stdin, so a piped “yes” does nothing.
  • It re-reads the file and checks its hash right before sending, so what you saw is exactly what leaves.
  • It re-runs the allowlist and daily cap against your current accounts.json.
  • It reloads each attachment from the recorded path and refuses if a file is gone or its size changed.
  • It refuses any message containing terminal escapes, bidirectional overrides or zero-width characters, which could make the screen show something other than what gets sent.

Entries that sit unapproved for seven days expire.

Keep the Agent Away From the Command

The /dev/tty check already stops an agent’s shell from approving. If your agent runs inside Claude Code, add a second layer so a permission prompt never offers the command at all. In .claude/settings.json (the permissions docs cover the deny list):

{
  "permissions": {
    "deny": ["Bash(mailbox-mcp approve*)", "Bash(npx mailbox-mcp approve*)"]
  }
}

Lock the Account After Untrusted Reads

If your agent triages an inbox, it reads text written by strangers, and some of that text is written to give the agent orders. Add untrustedReadLock to the same account:

"work": {
  "provider": "gmail",
  "email": "[email protected]",
  "approval": "external",
  "untrustedReadLock": "approval"
}

As soon as the agent reads a message the server can’t vouch for, every send from that account goes through the queue for the rest of the session, even on accounts where approval isn’t set. A message counts as vouched for only when the sender is on your trustedSenders list and the receiving server’s DMARC check passed. Nothing the agent can pass as an argument lifts the lock. Use "refuse" instead of "approval" to block sends entirely until the server restarts.

Add the Cheap Limits Too

Two more fields cost nothing and cap the damage from any mistake:

  • allowedRecipients: exact addresses and @domain patterns. Sends to anyone else are refused.
  • dailySendLimit: sends allowed per rolling 24 hours. The default is 100, and 0 blocks all sending.

For accounts the agent only needs to search, use "readOnly": true.

Read the Message Before You Type Yes

Approval protects what leaves your account, so the review is what counts. Read the body in the terminal, and for anything important, open it in your mail client too. A plain-text part can say something different from the HTML part a person sees.

The Question to Ask About Every Safety Rule

Once this is running, ask it of every guardrail you’ve given an agent: does the rule live in the prompt, or in the plumbing? A rule in the prompt depends on the model remembering it. If you’re deciding what to hand an agent in the first place, my guide to AI agents for business owners is the place to start. A rule in the tool holds after the context has been compacted, the session has run for hours, and the model has been told something convincing by a stranger’s email.

The code is on GitHub.

Related

Email Addresses to Set Up When Opening a Company
Why Every AI Agent Needs an RSS Hub (And How to Build One in WordPress)
What Is an AI Agent? A Plain-English Guide for Business Owners
lego buggy
Adding a Hardware Remote Control to Lego PoweredUP Control+ Sets
Gmail vs Fastmail: 2026 Comparison
Best Mailchimp Alternatives in 2026

Filed under: AI, Tech

About Jean Galea

I build things on the internet and write about AI, investing, health, and how to live well. Founder of AgentVania and the Good Life Collective.

Leave a Reply Cancel reply

Thanks for choosing to leave a comment. Please keep in mind that all comments are moderated according to our comment policy, and your email address will NOT be published. Please Do NOT use keywords or links in the name field.

Jean Galea

Founder | AI builder | Dad of three | Athlete

Follow @jeangalea

  • My Padel Journey
  • Affiliate Disclaimer
  • Cookies
  • Contact

Copyright © 2006 - 2026