Last month I wired Claude up to my email infrastructure. Not "Claude writes an email draft and I paste it somewhere" but the agent checks my domain status, sends the email, and reads back the delivery events, all from the chat.
The glue that makes this possible is MCP (Model Context Protocol), and the whole setup takes about five minutes. Here is exactly how to do it, plus what surprised me once agents could actually touch production infrastructure.
What MCP actually is
MCP is a small JSON-RPC protocol that lets an AI client (Claude, Cursor, Windsurf, your own agent) call tools exposed by a server. The server describes its tools with JSON schemas, the model picks a tool and fills in the arguments, and the client executes the call.
The important design decision is where the server runs. A lot of MCP servers are local stdio processes you install per machine. For anything talking to a hosted API, a hosted MCP server is the better shape: nothing to install, your API key is the auth, and every client that speaks HTTP can use it.
I use SMTPfast for transactional email, which ships a hosted MCP endpoint at https://smtpfa.st/api/mcp. That is what I will use in the examples, but the pattern applies to any hosted MCP server.
Step 1: Connect Claude Code
One command:
claude mcp add --transport http smtpfast https://smtpfa.st/api/mcp \
--header "Authorization: Bearer sf_your_api_key"
For Cursor, it is a snippet in .cursor/mcp.json:
{
"mcpServers": {
"smtpfast": {
"url": "https://smtpfa.st/api/mcp",
"headers": { "Authorization": "Bearer sf_your_api_key" }
}
}
}
That is the entire installation. No npm package, no local process, no version drift between machines.
Step 2: See what the agent can do
MCP servers self-describe. You can poke one with curl to see the tool list:
curl -sS https://smtpfa.st/api/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sf_your_api_key" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
The SMTPfast server exposes eight tools: send_email, list_emails, get_email, list_domains, verify_domain, list_suppressions, get_analytics, and list_contacts. The model reads those schemas and figures out the rest on its own.
Step 3: Just ask
With the server connected, I can type things like this into Claude:
"Check if my domain is verified, then send a test email from hello@mydomain.com to my personal address and tell me when it is delivered."
Behind the scenes the agent calls list_domains, sees the DKIM status, calls send_email, waits, then calls get_email to read the delivery events. I watch each tool call go by and approve it. No SDK, no glue code, no copy-pasting message IDs.
The debugging workflow is where this gets genuinely useful:
"Why did the email to jane@example.com bounce yesterday?"
The agent pulls the email, reads the bounce event with the SMTP diagnostic code, checks whether the address landed on the suppression list, and explains it in plain language. That used to be five minutes of clicking through a dashboard.
What surprised me
1. The approval step matters more than I expected. Most MCP clients show you each tool call before it runs. For read tools that feels like friction. For send_email it is exactly right. I would not connect a send-capable tool to an agent that runs unattended without scoping the key first.
2. Agents are great at chaining, bad at restraint. Ask a vague question and the agent will happily call four tools when one would do. Tight tool descriptions in the server matter as much as good prompts.
3. The server is the easy part. If your product already has a REST API, an MCP server is mostly a translation layer: tool schema in, API call out. The hard work (auth, rate limits, validation) already exists in the API. That is also why I prefer hosted MCP over stdio: it reuses everything the API already enforces, including that a compromised key can be revoked in one place.
Try it
If you want to reproduce this end to end: grab a free SMTPfast account (3,000 emails/month, no card), verify a domain, create an API key, and run the claude mcp add command above. The MCP docs cover the tool schemas and a few example prompts.
And if you are building a dev tool yourself: ship the hosted MCP endpoint. It is a weekend of work and it makes your product usable by every AI agent your customers already run.
Top comments (14)
Your point about scoping the key first is the thing I'd underline hardest, and I'd push it past revocation into capability. If one key can both send and read events, a prompt injection sitting in an inbox the agent reads can turn itself into a send. A read-only key for the debugging flow, plus a separate send key you attach only when you actually want mail going out, keeps the "agent chains eagerly" habit away from the one tool that leaves the building.
Yes, this is a great point!
thanks for sharing!
🙏
The approval step is the right instinct, but its security value depends on what exactly is being approved. The UI should bind approval to the final recipient set, sender, subject, body hash, attachments, and idempotency key—not merely to “call
send_email.” If the agent edits any field after approval, the token should become invalid and the client should ask again. That closes a subtle time-of-check/time-of-use gap.I would also split credentials by capability and policy: read-only diagnostics versus sending, verified sender identities, recipient/domain allowlists where practical, per-run and daily quotas, and short-lived tokens. Treat bounce messages, display names, and imported contact fields as untrusted content too; they can flow back into the model and influence the next action. Finally, log an immutable receipt connecting the approved payload hash to the provider message ID and delivery events. Human confirmation is useful, but payload-bound approval, scoped credentials, and replay-safe receipts are what make unattended retries and incident review trustworthy.
this is a very good idea!
Email is a perfect test for agent permissions because the action looks simple but the risk is external. The agent needs drafts, recipients, idempotency, and a clear human checkpoint before anything leaves the system.
yes! exactly this!
One extra boundary I would add is a dry-run/commit split. Let the agent resolve recipients, render the final MIME payload, and return a preview plus a stable request ID first; only a separate commit call should send it. The commit handler can reject reused IDs and enforce the sender, recipient set, and body hash it saw in the preview. That makes retries safe and gives the approval UI something concrete to bind to, instead of approving an abstract send_email capability.
Oh yes this is a good one too!
surprise. I will try it
awesome! let me know how it goes!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.