{"slug": "the-resend-alternative-for-ai-agents", "title": "The Resend alternative for AI agents", "summary": "MailKite launches an email API for AI agents that delivers parsed body and authentication verdict in a single webhook event, eliminating the extra fetch Resend requires. The service reduces the receive-reply loop to one round trip, targeting developers building autonomous email agents.", "body_md": "# The Resend alternative for AI agents\n\nResend has first-class sending DX and, since November 2025, real inbound email. But its inbound webhook is metadata only: an agent fetches the body with a second API call and derives SPF/DKIM trust itself. MailKite (which we build) pushes the parsed body and an auth verdict in one event, so an agent's receive→reply loop is a single round trip. For developers giving an autonomous agent its own inbox.\n\nConcretely: on Resend, `email.received`\n\nfires with the sender, subject, and attachment stubs, and then you call `resend.emails.receiving.get(email_id)`\n\nto pull the actual `text`\n\nand `html`\n\n. Two hops before your model reads a word, and the SPF/DKIM/DMARC result an agent needs to decide whether to trust the message isn’t in the event at all. For a human-facing app that’s a shrug. For an autonomous agent running a receive→think→reply loop, every extra hop and every “derive it yourself” is a place the loop can stall or misjudge a spoofed sender. Here’s that gap in one picture, then the whole MailKite side in about 25 lines.\n\nHere’s the bring-your-own-agent loop, whole. Email in, verify the signature, hand the parsed body to your model, reply through the same client. It runs as pasted on Node 18+ (`npm install mailkite express`\n\n), and the full version lives in a [runnable demo repo](https://github.com/mailkite/demo-resend-ai-agent):\n\n``` python\nimport express from \"express\";\nimport { MailKite } from \"mailkite\";\n\nconst app = express();\nconst mk = new MailKite(process.env.MAILKITE_API_KEY);\nconst SECRET = process.env.MAILKITE_WEBHOOK_SECRET;\n\napp.use(\"/hooks/agent\", express.raw({ type: \"application/json\" }));\n\napp.post(\"/hooks/agent\", async (req, res) => {\n  // signature check, replay window, constant-time compare — one call\n  if (!MailKite.verifyWebhook(req.headers[\"x-mailkite-signature\"], req.body, SECRET)) {\n    return res.sendStatus(401);\n  }\n  res.sendStatus(200);                    // ack fast; run the agent out of band\n\n  const event = JSON.parse(req.body);\n  if (event.type !== \"email.received\") return;\n\n  // the body and the auth verdict are already in the event — no second fetch\n  const answer = await runAgent({\n    task: event.text,                     // parsed body, right here\n    from: event.from.address,\n    trusted: event.auth.spf === \"pass\" && event.auth.dmarc === \"pass\",\n  });\n\n  await mk.send({\n    from: event.to[0].address,            // reply from the address it was sent to\n    to: event.from.address,\n    subject: `Re: ${event.subject}`,\n    inReplyTo: event.id,                  // threads the reply\n    html: answer.html,\n  });\n});\n\napp.listen(3000);\n```\n\nThat’s a fully autonomous email agent: it hears, it thinks, it answers, with the body and the SPF/DKIM/DMARC result both in the event that woke it up. `mk.send()`\n\nreturns `{ id, status }`\n\nso you can log the outbound message, and the identical handler shape exists for Python, Ruby, Go, PHP, and Java; see the [receiving docs](/docs/receiving) and [sending docs](/docs/sending). [Open it in StackBlitz](https://stackblitz.com/github/mailkite/demo-resend-ai-agent?file=server.mjs) to run real Node in a browser tab.\n\n## Where Resend wins for agents, honestly\n\nResend has the best sending developer experience in this category, and I’m not going to pretend otherwise. If your agent’s job is mostly to *send*, Resend is a genuinely great pick:\n\nThis post isn’t “Resend is bad.” It’s “Resend was built send-first, and its inbound half asks the agent builder to do the assembly.”\n\n## What Resend asks of an agent builder\n\nResend’s inbound is real and shipped, but the shape matters for an agent. The webhook is metadata only. Resend’s own docs say it plainly: *“Webhooks do not include the email body, headers, or attachments, only their metadata.”* So the receive step is a verify, then a fetch, then your own trust check, in Resend’s idiom:\n\n```\n// Resend inbound: verify the Svix signature, then FETCH the body (it isn't in the webhook)\nimport { Resend } from \"resend\";\nimport { Webhook } from \"svix\";              // Resend signs inbound webhooks with Svix\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst wh = new Webhook(process.env.RESEND_WEBHOOK_SECRET);\n\napp.post(\"/hooks/inbound\", async (req, res) => {\n  const evt = wh.verify(req.rawBody, {\n    \"svix-id\": req.headers[\"svix-id\"],\n    \"svix-timestamp\": req.headers[\"svix-timestamp\"],\n    \"svix-signature\": req.headers[\"svix-signature\"],\n  });\n  res.sendStatus(200);\n  if (evt.type !== \"email.received\") return;\n\n  // the event carries metadata: from, to, subject, attachment stubs — no body.\n  // pull the stored message to get text/html:\n  const { data: mail } = await resend.emails.receiving.get(evt.data.email_id);\n\n  // and there's no SPF/DKIM/DMARC verdict in the payload — you derive trust yourself\n  await runAgent({ task: mail.text, from: evt.data.from });\n});\n```\n\nNothing here is hard. But notice what the agent path accumulates: a second network call before the model sees the body, an attachment fetch after that if the message has one, and a trust decision you make from raw headers because the event doesn’t hand you an SPF/DKIM/DMARC result. Stack the inbound steps up and the assembly is visible:\n\n## The comparison, no adjective inflation\n\n| Resend | MailKite | |\n|---|---|---|\n| Inbound email | Yes, shipped Nov 2025 | Yes |\n| Body in the webhook | Metadata only; fetch via API | Parsed `text` + `html` in the event |\n| SPF/DKIM/DMARC in payload | Not in the inbound event | `auth` block inline |\n| Round trips to read one email | Webhook + a `GET` | One pushed event |\n| Reply threading | Send API | `inReplyTo` , returns `{ id, status }` |\n| Sandbox / approval | None, instant production | None, DNS-verify then send |\n| Domains on free tier | 1 | No per-domain fee |\n| Free tier | 3,000/mo, 100/day cap | 3,000/mo (in + out) |\n| Run the agent loop for you | You host it (MCP for tools) | Route `action: 'agent'` on a queue |\n| React templating | React Email (they maintain it) | Bring your own / templates |\n\nThe through-line: Resend wins send-side DX, React Email, and instant production, and if you’re sending-first it’s a great tool. MailKite wins the *receive* side an agent leans on: the parsed body and a trust verdict arrive in one event, so the loop is a single round trip. Two of those rows (a fleet of agents each on its own domain hits Resend’s one-domain free tier; MailKite has no per-domain fee) also matter once you run more than one agent.\n\n## What actually hits your agent’s webhook\n\nThe same inbound email, delivered parsed, with the trust result already resolved. No second fetch, no header parsing:\n\n```\n{\n  \"id\": \"msg_2Hk9…\",\n  \"type\": \"email.received\",\n  \"from\": { \"address\": \"ada@example.com\" },\n  \"to\": [{ \"address\": \"agent@myapp.ai\" }],\n  \"subject\": \"Re: invoice #1042\",\n  \"text\": \"Looks good — approved!\",\n  \"html\": \"<p>Looks good — approved!</p>\",\n  \"threadId\": \"<a1b2c3@mail.example.com>\",\n  \"auth\": { \"spf\": \"pass\", \"dkim\": \"pass\", \"dmarc\": \"pass\", \"spam\": \"ham\" },\n  \"attachments\": [\n    { \"id\": \"msg_2Hk9…:0\", \"filename\": \"po.pdf\", \"contentType\": \"application/pdf\",\n      \"size\": 18213, \"url\": \"https://api.mailkite.dev/att/2Hk9…/0?exp=…&sig=…\" }\n  ]\n}\n```\n\nThat `auth`\n\nblock is load-bearing for an agent. `From:`\n\nis plain text and trivially spoofable, so the email body is untrusted input, never instructions; the moment your agent *follows* what a message says, that body is a prompt-injection vector. Checking `auth`\n\nbefore you weight a sender’s instructions is necessary but not sufficient. The real fix is architectural, and it’s the whole point of [agent inbox security by design](/blog/agent-inbox-security-by-design/): read that before either loop acts on anything that matters.\n\n## One more option: let MailKite run the agent\n\nBoth paths above have you hosting the model loop. On MailKite you can also make the route itself the agent. A route with `action: \"agent\"`\n\ncarries an `agentPrompt`\n\n, and MailKite, which we build, runs the model loop for you on a durable Cloudflare Queue with its own execution budget, a per-run tool-round cap, a five-minute reaper, and a full transcript you can drill into per route:\n\n```\nawait mk.createRoute({\n  match: \"support@myapp.ai\",\n  action: \"agent\",\n  agentPrompt: \"Answer billing questions from the docs. Escalate anything else to humans@myapp.ai.\",\n});\n```\n\nThe system prompt bakes in the safety rules: the body is untrusted, at most one reply, never reply to no-reply senders. Bring-your-own wins when the agent’s brain is your code; the built-in route wins when the job is “read this inbound mail, answer or escalate” and you’d rather not run the infrastructure.\n\n## FAQ\n\n**Does Resend support inbound email?**\nYes, since November 2025. An `email.received`\n\nwebhook fires when mail arrives at your Resend-managed or MX-configured domain. The important detail for an agent: the webhook carries metadata only (sender, subject, attachment stubs). To read the body you call the received-emails API with the `email_id`\n\n. MailKite delivers the parsed body in the webhook itself.\n\n**What’s the actual difference for an AI agent?**\nRound trips and trust. On Resend the agent gets a metadata webhook, fetches the body on a second call, and derives SPF/DKIM/DMARC itself. On MailKite the parsed `text`\n\n, `html`\n\n, a resolved `threadId`\n\n, and an `auth`\n\nverdict arrive in one signed event, so the receive step is a single hop and the trust signal is already there.\n\n**Is Resend a good choice for sending from an agent?**\nYes. Resend’s send API and React Email are excellent, production access is immediate with no sandbox, and there’s an official MCP server. If your agent is send-first, Resend is a strong pick. The gap this post is about is the inbound half of an autonomous loop.\n\n**Can I keep using React Email with MailKite?**\nYes. React Email compiles to plain HTML that works with any provider, so render your components to a string and pass it as `html`\n\nto `mk.send()`\n\n. You’re not locked out of Resend’s authoring tools by receiving on MailKite.\n\n**Do I have to wait for approval to start on MailKite?**\nNo, same as Resend on this point. Verify your domain over DNS (SPF + DKIM to send, MX to receive) and you can send to anyone. There’s no sandbox and no per-domain fee; the free tier is 3,000 messages a month across inbound and outbound. See the [quickstart](/docs/quickstart).\n\nIf Resend has your agent fetching every inbound body on a second call and reconstructing SPF/DKIM by hand, there’s a shorter loop. Clone the [demo repo](https://github.com/mailkite/demo-resend-ai-agent) (or [run it in your browser](https://stackblitz.com/github/mailkite/demo-resend-ai-agent?file=server.mjs)), then [point a domain at MailKite](/docs/quickstart) and your agent’s next inbound email arrives parsed, authenticated, and ready to answer.\n\n*Related: the pillar on giving your agent an inbox, agent inbox security by design, and the full MailKite vs Resend comparison.*", "url": "https://wpnews.pro/news/the-resend-alternative-for-ai-agents", "canonical_source": "https://mailkite.dev/blog/resend-for-ai-agents/", "published_at": "2026-07-04 00:00:00+00:00", "updated_at": "2026-07-04 00:59:28.227184+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-infrastructure"], "entities": ["MailKite", "Resend", "SPF", "DKIM", "DMARC", "StackBlitz", "Node", "Express"], "alternates": {"html": "https://wpnews.pro/news/the-resend-alternative-for-ai-agents", "markdown": "https://wpnews.pro/news/the-resend-alternative-for-ai-agents.md", "text": "https://wpnews.pro/news/the-resend-alternative-for-ai-agents.txt", "jsonld": "https://wpnews.pro/news/the-resend-alternative-for-ai-agents.jsonld"}}