Brevo logo vs MailKite logo
Alternative to Brevo

Inbound as one event with a trust verdict already attached — not an items[] batch you grep for SPF.

Brevo (formerly Sendinblue) is a marketing suite with a transactional API, and it can receive: Inbound Parsing POSTs mail as an items[] array with a genuinely clean ExtractedMarkdownMessage body. But there's no normalized SPF/DKIM/DMARC verdict — that lives only in raw Headers you string-parse — and the reply is a separate product. MailKite hands an agent one email.received event with an auth block and a receive→reply loop already assembled.

A fair take on Brevo

Brevo is a strong marketing platform: campaigns, CRM, automation, SMS, and WhatsApp behind one API key is real leverage for a marketing-shaped agent, and its ExtractedMarkdownMessage — the reply body with quoted history and signature split off — is a nicer LLM input than most inbound APIs hand back.

How it works

Brevo vs MailKite, in one diagram

Brevo email in Brevo inboundreply.you MX items[] webhookno auth verdict your appparse + dig auth Brevo APIsend reply MailKite email in MX edgeparse + auth JSON webhookauth block your agentyour model mk.send()reply out Blue = operated by MailKite. On Brevo the auth verdict isn't a field; you rebuild it from raw headers first.
Why teams switch

What MailKite does differently

A normalized auth verdict, not a header grep

Brevo's inbound gives you a SpamScore float (rspamd) but no SPF/DKIM/DMARC field — the results live only as raw Received-SPF and Authentication-Results lines inside Headers, so you regex out the trust verdict yourself. MailKite normalizes it into event.auth at the edge before your agent decides how much to trust a sender.

One event, not a batch to iterate

Brevo POSTs an items[] array you loop over. MailKite delivers one email.received event per message with the body, threadId, and auth already resolved — the shape an agent actually consumes.

Reply is in the same API, not a second product

On Brevo the answer goes out through the separate transactional send API (a different surface new accounts open a support ticket to activate), and you set In-Reply-To / References yourself. MailKite's mk.send({ inReplyTo }) replies and threads from the same client.

A built-in agent loop, and unlimited domains free

A MailKite route with action:'agent' runs the receive→think→reply loop on a durable queue with a transcript you can drill into — no wiring a model to a transactional API. Every plan gets unlimited domains at no per-domain cost.

Side by side

MailKite vs Brevo

MailKite Brevo
Product center of gravity Inbound email → webhook Marketing suite (campaigns, CRM, automation)
Inbound shape One email.received event items[] array (batch) via webhook or poll
Auth verdict (SPF/DKIM/DMARC) Normalized auth block Not a field — grep raw Headers yourself
Spam signal spam: ham/spam plus auth SpamScore float (rspamd)
Body for the model Decoded text + html ExtractedMarkdownMessage (clean, nice)
Agent loop built in Optional route action:'agent', or BYO None — wire model + transactional send
Reply + threading mk.send({ inReplyTo }) resolves it Separate transactional API; set headers yourself
Webhook auth Signed; verifyWebhook() in one call Guard the endpoint yourself

Competitor capabilities change — we re-audit these tables regularly. Spot something out of date? Tell us and we'll fix it.

Show the payload

What actually hits your webhook

Brevo parses the body nicely but leaves the trust verdict in raw headers and the reply in another product. MailKite's one event carries a normalized auth block, threadId, and signed attachment URLs — and you reply from the same API.

Brevo Inbound Parsing (items[] webhook — no auth verdict)
http
POST /your-webhook   Content-Type: application/json

{
"items": [
{
"From": { "Address": "ada@example.com", "Name": "Ada" },
"To": [{ "Address": "agent@reply.myapp.ai" }],
"Subject": "Re: invoice #1042",
"RawTextBody": "Looks good — approved!\n\nOn Tue… wrote:\n> …",
"ExtractedMarkdownMessage": "Looks good — approved!",
"SpamScore": 0.7,
"Headers": {
"Received-SPF": "pass (sender IP is …)",
"Authentication-Results": "… spf=pass … dkim=pass … dmarc=pass"
},
"Attachments": [ … ]
}
]
}
// SpamScore is a float, not pass/fail. To trust the sender you
// regex spf=/dkim=/dmarc= out of Headers yourself — then reply
// over the separate transactional API and set In-Reply-To by hand.
MailKite
json
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=…" }
]
}
The price advantage

Unlimited domains. One quota. Free to start.

MailKite

  • Free: 3,000 emails/mo (in + out)
  • Unlimited domains on every plan
  • Pro $20/mo → 50,000, graceful overage

Brevo

  • Free plan: 300 emails/day
  • Paid transactional from around $9/mo
  • Marketing automation caps contacts on lower tiers

Brevo prices for a marketing suite; MailKite prices one combined inbound + outbound volume with domains always free. Confirm current numbers on each pricing page before you commit.

See full MailKite pricing →

Switch in an afternoon

Moving from Brevo

  1. 1

    Point MX at MailKite (or use a managed subdomain)

    Where Brevo had you point a reply subdomain's MX at inbound1/inbound2.sendinblue.com, add the MailKite MX records instead — or start on a managed subdomain while DNS propagates. No support ticket to enable sending.

  2. 2

    Replace the items[] loop with one event

    Delete the for (item of items) loop and the header-grepping trust check. Read one email.received event: event.text, event.from.address, and event.auth.spf/dkim/dmarc already normalized.

  3. 3

    Verify the signature and reply in the same API

    Check x-mailkite-signature with verifyWebhook(), then reply with mk.send({ inReplyTo: event.id }) — threading resolved, SPF/DKIM aligned to your own domain, no second product to activate.

Questions

Can Brevo receive inbound email for an agent?

Yes. Brevo's Inbound Parsing points a subdomain's MX at inbound1/inbound2.sendinblue.com and POSTs parsed mail as an items[] array, each item carrying the body, Headers, Attachments, and a SpamScore. MailKite delivers the same message as a single email.received event with a normalized auth block.

Does Brevo's inbound payload include an SPF/DKIM/DMARC verdict?

Not as a field. SpamScore is a spam float, and the SPF/DKIM results live only as raw lines (Received-SPF, Authentication-Results) inside Headers, so you parse the verdict yourself. MailKite normalizes it into auth: { spf, dkim, dmarc, spam } at the edge.

Can I keep marketing on Brevo and run the agent on MailKite?

Yes — they're not exclusive. Run campaigns, CRM, and lifecycle automation on Brevo, and point the agent's address (a subdomain or a separate domain) at MailKite so it receives parsed JSON with an auth block and replies over the same send API.

Go deeper

The Brevo alternative for AI agents →

The long-form take on our blog — receipts, runnable code, and where we won't overclaim.

Try MailKite free — keep Brevo running until you're ready.

Point a domain, drop in a webhook URL, receive your first email. Unlimited domains, no credit card.