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.
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.
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.
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.
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 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.
| 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.
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.
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. 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=…" }
]
} 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.
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.
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.
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.
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.
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.
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.
The Brevo 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.