CloudMailin MCP - Let AI interact with your CloudMailin Email Address
Steve Smith
22 May 2025
Just over a year ago we published our first post about MCP, showing how you could let AI interact with your CloudMailin email address. Near the top of that post we added a caveat: "this is moving fast, this article is probably out of date by the time you read it". That turned out to be the most accurate sentence we published all year.
The server in that post was a local Node process. You cloned a repository, ran
npm install and npm run build, pointed your MCP client at the compiled
JavaScript, and then, and this is the part that never sat right with us,
pasted your CloudMailin API key into a JSON config file as an environment
variable. It worked. People used it, and what they did with it shaped
everything that follows. But an API key sitting in plain text in a desktop
config file is not how we wanted anyone to connect an AI agent to their email.
So we rebuilt it as a hosted service. CloudMailin's MCP server now lives at
https://mcp.cloudmailin.com/mcp. There is nothing to install, nothing to
build, and no key to copy anywhere. You give your MCP client one URL, it opens
a CloudMailin sign-in page in your browser, and you approve exactly what it is
allowed to do. The old npm package is now deprecated, and this post is the
proper introduction the hosted server never had.
The server exposes six tools, and the list is deliberately short for what it
covers. Four of them carried straight over from last year's local server:
listAddresses, listMessages, listSentMessages, and sendEmail, markdown
support and all. Only two are genuinely new, listDomains and
listOutboundAccounts, and they landed after the hosted server was already
running. The count matters less than how they reached you, which is the whole
point of hosting this instead of shipping you a package to run: more on that
below.
| Tool | Scope | What it does |
|---|---|---|
listAddresses |
read | Lists every inbound address in the account, with its ID and the HTTP endpoint it delivers to |
listMessages |
read | Delivery status of email received by an address, including the HTTP response your endpoint returned |
listSentMessages |
read | Outbound delivery status: delivered, deferred, or bounced, with the receiving server's SMTP response |
listDomains |
read | Every sending domain's SPF, DKIM, and Return-Path status individually, plus the exact DNS records still missing |
listOutboundAccounts |
read | Your sending accounts, for picking one when more than one exists |
sendEmail |
send | Sends email through one of your verified sending domains, tracked like any other outbound message |
Between them, these cover the loop an agent actually needs: what addresses
exist, what arrived and whether your application accepted it, whether a
sending domain is actually ready to send from (and if not, exactly what's
missing), whether what you sent was delivered, and the ability to send
something new. sendEmail takes markdown and converts it into proper HTML and
plain text parts, because asking a language model to hand-assemble multipart
MIME is asking for trouble.
listDomains in particular turns domain setup into a guided conversation
instead of a support ticket. It doesn't just report a domain as "unverified":
it checks SPF, DKIM, and Return-Path individually, so an agent can tell you
specifically which of the three is still missing for mail.acme.com, hand
back the exact CNAME or TXT record for that one, and check again once you've
added it. You can go from "why can't I send from this domain" to a fully
configured one without leaving the conversation, let alone finding the right
page in a dashboard.
Just as important is what isn't there. There are no tools for changing account settings, managing team members, or deleting anything. An agent connected through MCP can observe email flow, check on domain setup, and send messages, and that is all. If you need the full surface, the REST API hasn't gone anywhere; the MCP server is intentionally a narrower doorway. A small tool list is also easier for a model to use well: fewer tools means fewer ways to pick the wrong one.
listDomains and listOutboundAccounts are the two that didn't exist when
this server first went up. We added them the very next day, and every client
already connected got them immediately: no update, no reinstall, no
re-approving the OAuth grant. That's a real, practical difference from the old
local server, where a new tool meant git pull, npm install, and a rebuild
before you could use it. Hosted means we can hand you new capability the moment
it ships.
The standard pattern for connecting an agent to a service has been: generate
an API key, paste it into a JSON file, hope. Look at almost any MCP config in
the wild and you'll find an env block holding a long-lived secret with full
account access. Those files get committed to dotfiles repositories, synced
between machines, pasted into chat windows when something breaks, and swept
into backups forever. A key in that position usually has every permission your
account offers and no expiry date.
There are ways to do this better. Storing MCP secrets in your OS keychain instead of plaintext is a real improvement, and worth doing for any server that requires one. But the best secret is the one you never have to store at all.
The hosted server replaces that with OAuth 2.1 and PKCE. In plain terms, here is what happens the first time your client connects:
PKCE (proof key for code exchange) is the piece that makes this safe for desktop apps and command line tools. The client proves it is the same process that started the flow, so an intercepted authorization code is useless to anyone else, and there is no client secret to ship or store.
A few properties fall out of this design that we think matter more than any individual tool:
An agent with email access deserves the same care as a person with email access. That one sentence drove most of the decisions above.
The MCP page has one-click installs and copyable snippets for each client; here are the short versions.
Claude Code takes one command:
claude mcp add --transport http cloudmailin https://mcp.cloudmailin.com/mcp
The first tool call opens the OAuth sign-in in your browser. If you ever need
to re-authenticate, run /mcp inside Claude Code.
claude.ai and Claude Desktop treat MCP servers as connectors:
https://mcp.cloudmailin.com/mcpCursor reads .cursor/mcp.json (Cursor Settings → MCP → New MCP server
gets you there), and opens the sign-in on first use:
{
"mcpServers": {
"cloudmailin": {
"url": "https://mcp.cloudmailin.com/mcp"
}
}
}
VS Code can add it straight from the terminal:
code --add-mcp '{"name":"cloudmailin","type":"http","url":"https://mcp.cloudmailin.com/mcp"}'
Windsurf uses the same JSON shape as Cursor in its mcp_config.json
(Settings → Cascade → MCP servers), with serverUrl as the key instead of
url.
And if you're building your own agent, anything that speaks Streamable HTTP and supports OAuth works out of the box. There is no CloudMailin-specific SDK to integrate; the URL is the integration.
The clearest way to see the value is a few real prompts.
"What landed at support@ this morning, and did we accept all of it?" The
agent calls listAddresses to resolve support@ to an address ID, then
listMessages for that address. Because each record includes the HTTP
response your endpoint returned, the answer isn't just who wrote in and about
what. It can also be "your webhook returned a 500 for two of them around
6am". We built the delivery view in the dashboard for humans; it turns out
agents want exactly the same information, just conversationally.
"Did the password reset reach kate@acme.com?" This question used to mean
grepping logs or clicking through a dashboard. The agent calls
listSentMessages and answers from the delivery record: accepted, along with
the receiving server's actual SMTP response, or the precise bounce reason if
it failed.
"Send her the receipt, and CC accounts." With the send scope granted, the
agent composes the message in markdown and calls sendEmail. It goes out
through your verified domain with proper HTML and plain text parts, and it
appears in your outbound history tracked like any other message, so the next
"did it arrive?" question works on it too.
"Walk me through getting mail.acme.com ready to send from." The agent
calls listDomains, sees SPF and Return-Path are verified but DKIM isn't,
reads back the exact DKIM record to add, and can check again on request once
you've added it, guiding you to a fully verified domain a step at a time.
None of these required an API integration, a polling loop, or copying message IDs between systems. That is the entire pitch of MCP, and email happens to be a domain with an unusual amount of tedium worth removing.
There's a wave of new products right now offering inboxes built specifically for AI agents, and we understand the appeal of starting fresh. We'd gently argue the opposite position: the hard part of giving an agent email was never the agent-facing API. It's the email.
Email is a forty-year accumulation of edge cases. Real-world messages arrive with malformed MIME boundaries, nested multiparts, attachments of every size and type, and character encodings that predate Unicode (we once wrote up Outlook emitting windows-1258 for messages that had nothing to do with Vietnamese). Senders retry in odd patterns. Spam and abuse arrive constantly, and adapt when blocked. Parsing all of that into clean, structured data your application, or your agent, can trust is not a feature you bolt on afterwards. It is the product, and it takes years of production traffic to get right.
That is the platform this MCP server is a thin layer over. CloudMailin has been receiving email and delivering it to applications as structured data since 2010: sixteen years, billions of messages, 99.99% uptime, attachment handling into S3-compatible storage, spam scoring and sender authentication checks on the way in, and a SOC 2 Type 2 examination behind all of it.
To be clear about what this is and isn't: CloudMailin is not repositioning itself as an AI company. We build email infrastructure, and MCP is one more way to use it, alongside the webhook POSTs, the REST API, and SMTP. The MCP server gets the same treatment as any other production surface, which is exactly why we took the time to do OAuth properly instead of shipping the quick version.
An honest note to close on: MCP is still young. The specification keeps moving, and OAuth support varies between clients. Some handle the sign-in flow seamlessly, others are still catching up, and occasionally you'll need to re-authenticate for no obvious reason. If you hit something odd, updating your client is usually the fix; the ecosystem improves monthly.
The tool surface is also a starting point, not a final shape, something we've already proven once by adding two tools the day after launch with nobody needing to lift a finger. We keep it as small as it can be at any given time on purpose: a tight tool list is easier for a model to use well and easier for you to reason about when you're deciding what to grant. What we add next will be guided by what people actually ask their agents to do, which is exactly how usage of the first version shaped this one.
If you'd like to try it, the MCP page has install snippets for every client mentioned here, and a free CloudMailin account is enough to connect and experiment. If you build something interesting with it, or hit a rough edge we should know about, get in touch. The last version of this server was shaped by the people who used it, and we'd like this one to be too.
Steve Smith
14 Jul 2026
Steve Smith
22 May 2025
Steve Smith
2 Jun 2026
Steve Smith
7 Jul 2026