MailKite
Get your API key
All guides Agent email

Agent email with Amazon SES

Give an AI agent its own inbox and it can hold a real email conversation — field a support request, follow up on a thread, confirm a booking. This guide sets that up with Amazon SES, then shows the same thing the MailKite way, where the agent gets email as native tools over MCP.

What you'll need

  • An AWS account with SES moved out of the sandbox, and a verified domain.
  • An agent runtime that can call tools (function calling or MCP).
  • For inbound: SES receiving in a supported region, plus SNS or S3 + Lambda.

Part 1 — Give your agent an inbox with Amazon SES

SES gives your agent email, but it takes the most wiring of any provider here: outbound is a signed API call, and inbound is a separate pipeline you assemble yourself. Here's the shape of it.

1. Send from the agent

Expose sending as a tool. The implementation calls SES v2 SendEmail, signing the request with SigV4 — the AWS SDK handles the signing, or you build it with the CLI. See Send email with Amazon SES for the full setup:

send-email.js
// Wrap SES v2 SendEmail as a tool. The impl signs the request with SigV4
// (the AWS SDK or a signing library does this for you) and POSTs to the
// regional SES endpoint.
import { SESv2Client, SendEmailCommand } from "@aws-sdk/client-sesv2";

const ses = new SESv2Client({ region: "us-east-1" });

async function send_email({ to, subject, html }) {
await ses.send(new SendEmailCommand({
FromEmailAddress: "agent@yourdomain.com",
Destination: { ToAddresses: [to] },
Content: {
Simple: {
Subject: { Data: subject },
Body: { Html: { Data: html } },
},
},
}));
}

2. Wire up inbound

There's no inbox to poll. You point the domain's MX at SES and create a receipt rule set that delivers incoming mail to SNS (or S3 + Lambda):

inbound-rule
# Inbound is a separate build: a receipt rule set that delivers
# raw mail to SNS (or S3 + Lambda). Verify the domain's MX to SES first.
aws ses create-receipt-rule-set --rule-set-name agent-inbound

aws ses create-receipt-rule --rule-set-name agent-inbound --rule '{
"Name": "to-sns",
"Enabled": true,
"Recipients": ["support@yourdomain.com"],
"Actions": [{ "SNSAction": { "TopicArn": "arn:aws:sns:us-east-1:...:agent-mail" } }]
}'

3. Parse the raw MIME, then feed the agent

SNS or Lambda hands you the raw RFC 822 message — you decode the headers and parts yourself before anything reaches the model. See Amazon SES inbound for the full pipeline:

handle-inbound.js
// SNS/Lambda hands you the raw MIME message — parse it, then feed
// the agent. There is no clean JSON; you decode headers and parts yourself.
import { simpleParser } from "mailparser";

export async function handler(event) {
const record = JSON.parse(event.Records[0].Sns.Message);
const mail = await simpleParser(record.content); // raw RFC 822
agent.handle({
from: mail.from.text,
subject: mail.subject,
body: mail.text,
});
}

That's an agent inbox on SES: wrap the signed send call as a tool, stand up a receipt rule to SNS/Lambda, parse the MIME, and let your agent run the conversation.

Part 2 — The same, the MailKite way

No SigV4 to sign, no receipt rules, no SNS or Lambda, no MIME to parse. MailKite is MCP-native, so your agent doesn't call a REST API you wrapped by hand — it speaks MCP and gets email as first-class tools. Connect the server once and the same send-and-reply loop is a few tool calls.

1. Connect the MCP server

Add the hosted server. On the first connect it signs you in over OAuth in the browser — no key to copy — or pass your account key for headless runs:

connect
# Hosted MCP server — OAuth in the browser on first connect, no key to copy
claude mcp add --transport http mailkite https://mcp.mailkite.dev/mcp

# Headless / CI — pass your account key instead of the browser flow
claude mcp add --transport http mailkite https://mcp.mailkite.dev/mcp \
--header "Authorization: Bearer mk_live_..."

Any MCP client — Cursor, Claude Desktop, Cline, Zed — takes the same URL:

mcp config
{
"mcpServers": {
"mailkite": { "url": "https://mcp.mailkite.dev/mcp" }
}
}

2. Send from your agent

The agent calls mailkite_send over any verified domain — HTML, text, cc/bcc, attachments, and in-thread replies. Pick AI in the card for the agent's view, or any language to make the same send from your own code:

send
import { MailKite } from "mailkite";

const mk = new MailKite(process.env.MAILKITE_API_KEY);

const { id, status } = await mk.send({
from: "hello@myapp.ai",
to: "ada@example.com",
subject: "Your invoice #1042",
html: "<p>Thanks! Receipt attached.</p>",
});
Install Docs →
response
202 Accepted
{ "id": "msg_2Hk9…", "status": "queued" }

3. Receive — or hand the whole inbox to the agent

Every address on the domain is receivable. The agent can read inbound with its own tools, or you turn an address into an inbox agent with one route — the model reads and replies on its own:

create the agent route
import { MailKite } from "mailkite";

const mk = new MailKite(process.env.MAILKITE_API_KEY);

// One route turns an address into an AI inbox agent — the prompt
// is the program, and unresolved mail escalates to a human.
await mk.createRoute({
match: "support@myapp.ai",
action: "agent",
agentPrompt:
"Answer billing and account questions for myapp.ai. Reply in-thread. " +
"Escalate anything you can't resolve to humans@myapp.ai.",
agentForwardTo: ["humans@myapp.ai"],
});
Install Docs →
read inbound
// Or read inbound yourself — the agent has tools for it
mailkite_list_messages({ limit: 20 }) // newest first
mailkite_get_message({ id: "msg_2Hk9…" }) // full body, headers, attachment links

Same key manages the domain too — mailkite_create_domain, mailkite_verify_domain — so the agent can provision its own inbox end to end. See Connect your agent for the full tool list.

A little about MailKite

MailKite is programmable email for developers and AI agents. Connect the MCP server once and your agent can send over a verified domain, read its inbound as clean JSON, spin up new inboxes, manage domains, and become an inbox agent that answers mail on its own — all as native tools, no REST wrapper to maintain. It works the same over the SDKs, the CLI, or raw HTTP, and agent inboxes are on the free tier.

Next: Connect your agent for every MCP tool, or Set up your agent's email to go from zero to a working inbox.