Loops is a genuinely nice lifecycle- and transactional-email tool for SaaS: a visual editor, event-triggered loops, and free transactional sends. But it's send-only, so an autonomous agent has nowhere to receive the verification code or the reply it's waiting on. MailKite gives that agent a real address that arrives as one parsed JSON webhook, and sends from the same API.
Loops is one of the nicest developer experiences in product email right now — the visual editor is pleasant, the lifecycle-loops model maps cleanly to how SaaS onboarding works, and transactional sends are free on paid plans with clean Clerk/Stripe/Supabase integrations. If your job is sending lovely onboarding and product mail, Loops is a strong pick.
Loops sends the welcome, the drip, and the receipt well — but an agent's hard problem is receiving. MailKite gives an address that receives, so the code emailed to agent@myapp.ai lands somewhere the agent can read.
Parse an incoming email and reply to it with the same account, SDK, and shared quota. With Loops you'd bolt on a second, receiving provider and reconcile threading between two systems.
Inbound arrives as one JSON object — decoded text and HTML, a resolved threadId, signed attachment URLs, and an auth block (SPF/DKIM/DMARC/spam) so a fooled agent isn't a prompt-injection target.
Run every product and every agent address from one account at no per-domain cost, on every plan — instead of pricing by subscribed contacts.
| MailKite | Loops | |
|---|---|---|
| Product / lifecycle email | API templates, no visual builder | Excellent visual editor + loops |
| Transactional send | from/to/subject/html + inReplyTo | Template-based (transactionalId), free on paid plans |
| Inbound email (an agent's inbox) | Parsed JSON webhook per address | None — send-only |
| Read a verification code / reply | text + html + threadId delivered | Not possible without a second provider |
| SPF/DKIM/DMARC on inbound | auth block on every message | n/a (no inbound) |
| Reply threading | inReplyTo threads the reply | n/a (no inbound) |
| Run the agent for you | Route action: 'agent' on a queue | No |
| Per-domain fees | None — unlimited domains | Priced by subscribed contacts |
Competitor capabilities change — we re-audit these tables regularly. Spot something out of date? Tell us and we'll fix it.
Loops' send side is clean, but the loop stops at 'delivered.' MailKite POSTs the reply back as parsed JSON so the agent can read it and answer.
// Loops: outbound only. This is the whole send side, and it's nice.
await fetch("https://app.loops.so/api/v1/transactional", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LOOPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
transactionalId: "clfq6…", // a template you published in the Loops editor
email: "ada@example.com",
dataVariables: { code: "418207" }, // fills the template
}),
});
// …now the agent needs to READ ada's reply — or the code a service just mailed it.
// Loops has no endpoint for that. You add a second, receiving provider here. POST /your-webhook Content-Type: application/json
x-mailkite-signature: t=…,v1=… (HMAC-SHA256 — verify locally)
{
"id": "msg_2Hk9…",
"type": "email.received",
"from": { "address": "ada@example.com" },
"to": [{ "address": "support@myapp.ai" }],
"subject": "Re: invoice #1042",
"text": "Looks good — approved!",
"html": "<p>Looks good — approved!</p>",
"threadId": "<a1b2c3@mail.example.com>",
"auth": { "spf": "pass", "dkim": "pass", "dmarc": "pass", "spam": "ham" },
"attachments": [
{ "filename": "po.pdf", "contentType": "application/pdf",
"size": 18213, "url": "https://api.mailkite.dev/att/2Hk9…/0?sig=…" }
]
} Different jobs, different meters: Loops bills by contacts for product email; MailKite bills one combined in + out volume and never charges per domain. Many teams keep both.
Nothing to rip out — leave your onboarding, lifecycle loops, and transactional templates where they are. This adds the receiving half Loops doesn't cover.
DNS-verify the domain (MX to receive, SPF + DKIM to send), pick an address like agent@myapp.ai, and set a webhook. No sandbox or approval wait.
Verify x-mailkite-signature with verifyWebhook, read event.text / event.auth, and reply with mk.send() — or let a route with action: 'agent' run the loop for you.
No. Loops is send-only — marketing, lifecycle, and transactional outbound. Its 'incoming webhooks' receive events from platforms like Stripe and Clerk (not email), and its outbound webhooks report send-side events like delivered and bounced. There's no MX setup, no inbound parse, and no address that receives mail.
Probably not, if you use it for product email — its editor and lifecycle loops are genuinely good. This is about a different job: giving an autonomous agent its own inbox. Many teams keep Loops for onboarding and add MailKite for the agent's receiving loop.
Point a domain at MailKite, pick an address, and set a webhook. Inbound mail is parsed to JSON and POSTed as an email.received event with text, html, threadId, and an auth block — the agent reads the code directly and replies with mk.send().
The Loops alternative for AI agents →
The long-form take on our blog — receipts, runnable code, and where we won't overclaim.
Point a domain, drop in a webhook URL, receive your first email. Unlimited domains, no credit card.