Here's a test I now run on anything that touches my inbox.
Let the AI do a morning's email. Then close the chat, open Outlook, and look. Can you tell?
If you can, something's wrong. A thread has split in two. A message you never opened is marked as read. There are two copies of the same email in Sent, or none at all. Every one of those is small, and every one of them makes your mailbox a little less trustworthy than it was before.
I build and run mail and web servers for a living, and have done since 2002. That test is the reason I ended up writing my own email MCP server, Mailbox MCP. This post is the story of why, and the engineering lessons that came with it. Most of them apply to anyone building an MCP server that writes to something people already use.
The email connector that made me build my own
Claude turned out to be properly useful for the parts of my working day that are made of email. So I paid for an email connector to put it to work. In my own words, from the About page where I first told this story:
I started out on the Pro plan of another email connector for AI, and I wanted it to work. It couldn't do properly threaded replies or forwarding. Sending an attachment wasn't impossible, but it took forever: my AI had to base64-encode everything, which took ages and then generally failed. It was a good idea, badly executed.
That's what prompted me to build Mailbox MCP and do it the right way. I use it for everything now, on my business mailbox and my personal one.
Why would I want to give AI access to my email?
It's a fair question, and the first one most people ask. My answer is that email is where a huge amount of real work sits, buried. Not the writing. The finding, the remembering and the filing.
These are the kinds of things I ask for every day:
- "Find the thread where we agreed the price with the supplier, and tell me what we agreed."
- "Which emails from this week still need a reply from me? Draft the replies, but don't send them."
- "Forward yesterday's quote to Sam with the revised PDF attached."
- "File everything from the accountant under Finance."
Each of those is ten minutes of scrolling and searching that the AI does in seconds. The ones that matter most are the replies you've been meaning to write for a week. Ask the AI what you owe and you get a list, with drafts.
Then there's the worry, and it's a reasonable one. It's your real mailbox, shared with every other program you open it in, and sending can't be undone. So the better question is what an AI would have to do to deserve that access. My answer became the design rule for the whole product:
- Reading an email never marks it as read.
- Deleting moves to Trash, exactly as your mail client does, so it can be recovered.
- A draft lands in your real Drafts folder, where you can open it in Outlook, edit it and send it yourself.
- Replies thread properly, and sent mail appears in Sent exactly once.
If you'd rather the AI never sends anything, ask it for drafts only. They'll be waiting in Drafts like any other unfinished email.
The rule: the mail client is the oracle
The first line of the design spec says a user must not notice anything unusual about how their mail behaves, compared with Outlook or webmail. Then it makes that testable: do the work through the AI, open the same mailbox in a mail client, and anything that looks wrong there is a bug, whatever our own tests said.
That matters because the convenient implementation is nearly always the wrong one, and the damage shows up weeks later in a different program:
| The job | The convenient way | What a mail client does |
|---|---|---|
| Read a message | Fetch it, which marks it read | Leaves it unread unless you open it |
| Delete a message | Expunge it for good | Moves it to Trash |
| Save a draft | Keep it in the app's own database | Saves it in Drafts, editable anywhere |
| Send a message | Hand it to SMTP and stop | Files a copy in Sent, once |
| Find the Sent folder | Look for a folder called "Sent" | Asks the server which folder is Sent |
A bug that files no Sent copy is invisible to a test written against the code that failed to file it. So every feature that touches mailbox state ends with a person opening the mailbox in a real mail client and checking.
Replies are a checklist, not a feature
"Supports replies" and "replies correctly" are very different claims. Nobody notices at evaluation time that the References header is right. They notice three weeks later when their thread has fragmented into five.
A correct reply carries the parent's identity forward so every client can stitch the conversation together (RFC 5322, section 3.6.4):
Message-ID: <reply-789@example.com>
In-Reply-To: <parent-456@example.com>
References: <root-123@example.com> <parent-456@example.com>
Subject: Re: Revised quote
And that's just the start. The full list I built against:
-
In-Reply-ToandReferenceschained correctly, with long chains pruned - No
Re: Re: Re:stacking, including the prefixes other languages use (AW, SV, Antw, Odp and friends) - Reply-all that removes your own addresses and aliases from To and Cc
- The original quoted as plain text and as clean HTML, under a proper "On [date], [name] wrote:" line
- The
\Answeredflag set on the original, so Outlook shows the little reply arrow - The sent copy filed in the right Sent folder, exactly once
Attachments: stop base64-ing files through the model
This was the failure that cost me the most, so it's worth a little arithmetic.
Base64 turns every 3 bytes into 4 characters. If an AI attaches a file that way, it has to write out every one of those characters as output in the conversation. A 5 MB PDF becomes roughly 7 million characters. That's slow for a small file, and for a large one it's more than the conversation can hold. It never finishes, and you've paid for the tokens anyway.
So in Mailbox MCP, file bytes never travel through the model unless it needs to read them. The AI hands over a reference and the server fetches the bytes at send time:
{
"to": "sam@example.com",
"subject": "Revised quote",
"text": "Here's the revised quote we talked about.",
"attachments": [
{ "fileRef": "<an attachment ref from read_email>" },
{ "url": "https://example.com/terms.pdf" },
{ "uploadId": "<files someone dropped on a one-off upload page>" }
]
}
(Simplified, but those are the three real routes.) A file already in the mailbox, a file at a web address, or a file uploaded through a one-off link. None of them pass through the conversation, so they cost no tokens and arrive byte for byte.
Four IMAP lessons I learned the expensive way
1. Reading must not mark mail as read. IMAP has a way to fetch a message without touching its flags. RFC 3501 describes BODY.PEEK as:
An alternate form of
BODY[<section>]that does not implicitly set the\Seenflag.
Every read in Mailbox MCP is a peek. It sounds obvious. Get it wrong once and an AI "just looking" at your inbox silently clears every unread marker you were relying on, and you only find out when you go looking for the email you hadn't dealt with yet.
2. Find folders by their flag, never by their name. Sent might be called "Sent", "Sent Items", "Sent Messages" or something in another language. Servers that support RFC 6154 tell you which is which:
C: a1 LIST "" "*" RETURN (SPECIAL-USE)
S: * LIST (\HasNoChildren \Sent) "/" "Sent Items"
S: * LIST (\HasNoChildren \Trash) "/" "Deleted Items"
S: a1 OK LIST completed
Guess by name and sooner or later you file into a folder the user has never seen.
3. Ask what the server can do after you log in. One Dovecot server I tested advertised 4 capabilities in its greeting and 38 once logged in. Read the greeting and you never error. You just drop every provider onto the slow path forever, copying and deleting instead of moving, and guessing folder names instead of reading flags.
4. "Exactly once" in Sent is harder than it sounds. Some providers file their own copy of everything you send. Most plain IMAP hosts don't. Always add one and some users get duplicates; never add one and others get nothing. So after every send, Mailbox MCP searches Sent for that exact message. If the provider has already filed it, we add nothing. If not, we append one.
Microsoft 365, where a lot of tools quietly stop working
In 2022 Microsoft turned off password sign-in for IMAP and POP in Exchange Online, and many tenants have SMTP AUTH switched off too. A tool that logs in with a password and sends over SMTP simply can't reach those mailboxes.
Supporting them properly takes more than a sign-in button. Mailbox MCP signs in with Microsoft and sends through Microsoft Graph rather than SMTP, so it keeps working in a tenant where SMTP AUTH is off.
What I measured
I didn't want to claim any of this without numbers, so I measured against a live mailbox while building it:
- 26,930 messages read over IMAP in one session, across 6.63 GB
- 0 duplicate copies left in Sent Items
- About 10 seconds for a send to arrive at an external domain over SMTP
Every one of those is something you can check against your own mailbox, in your own mail client, which is rather the point.
What Mailbox MCP doesn't do
Worth knowing before you connect anything, rather than after:
- Attachments are capped at 20 MB per message, all files together. That limit is mine, not the provider's.
- Microsoft 365 shared or delegated mailboxes (the Full Access or Send As kind) can't be connected.
- It's not a backup tool. It doesn't export, copy or migrate a mailbox.
- It can't recover mail that's already been deleted.
- Calendar tools need their own connection. A mailbox on its own gets the email tools only.
Trying it
Mailbox MCP is a remote MCP server, so there's nothing to install. You connect a mailbox (sign in with Microsoft, a Gmail app password, or IMAP details from your mail client), then add one URL to your AI client. In Claude Code that's a single command:
claude mcp add --transport http --scope user work-mail \
https://mcp.mailbox-mcp.com/db/mcp/YOUR-MAILBOX-KEY
The same URL works in Claude, ChatGPT, Cursor, VS Code, Zed and anything else that speaks MCP. There's a free tier if you want to run my test on your own inbox: mailbox-mcp.com.
I'd genuinely like to hear from anyone else building MCP servers that write to things people already use. What's your oracle? What do you check, outside your own test suite, to know you haven't left a mess behind? Tell me in the comments.
This article was created with the help of AI. I wrote it with Claude, the assistant that runs my own inbox through Mailbox MCP, and every fact, figure and opinion in it is mine.
Top comments (0)