Elastic Email is one of the cheapest ways to send, and its Inbound Routing can receive: point your MX at it and it POSTs parsed fields to a URL. But that POST is unsigned form params with no SPF/DKIM/DMARC verdict, it's gated to the paid Pro plan, and there's no agent loop. MailKite (which we build) delivers the same message as one signed email.received event with a normalized auth block and a receive→reply loop.
Elastic Email's per-email price sits at the very bottom of the market, and it speaks both HTTP API and SMTP relay — for a send-heavy agent where outbound volume is the dominant cost, that's genuinely hard to beat. Its inbound parse is real too: body_text and body_html arrive already decoded.
Elastic Email's inbound POST has no SPF/DKIM/DMARC or spam field — the only signal is whatever an upstream relay stamped into the raw header_list, which you string-parse yourself. MailKite normalizes it into event.auth { spf, dkim, dmarc, spam } at the edge.
Elastic Email's form POST is unsigned, so anyone who learns your route URL can forge an email to it — guarding it (secret path, IP allowlist, token) is your job. MailKite signs every event; verifyWebhook() checks it in one call.
Elastic Email's Inbound Email Processing is a paid Pro feature, and inbound draws down your sending allowance. MailKite's free tier of 3,000 messages/mo covers inbound and outbound, with unlimited domains and no per-domain fee.
On Elastic Email you wire the model and the send API yourself, and set In-Reply-To/References by hand to thread. A MailKite route with action: 'agent' runs the loop for you, or bring your own and reply with mk.send({ inReplyTo }).
| MailKite | Elastic Email | |
|---|---|---|
| Inbound → parsed webhook | Yes — signed JSON event | Yes — form POST params |
| Inbound plan gate | Included; free tier covers inbound | Pro plan only; draws sending allowance |
| Auth verdict (SPF/DKIM/DMARC) | Normalized auth block | Not a field — grep raw header_list |
| Spam signal | auth.spam (ham/spam) | None in payload |
| Webhook authentication | Signed; verifyWebhook() in one call | Unsigned — guard the URL yourself |
| Body for the model | Decoded text + html | body_text + body_html (decoded) |
| Reply + threading | mk.send({ inReplyTo }) resolves it | Separate send API/SMTP; set headers yourself |
| Agent loop built in | Optional route action: agent, or BYO | None — wire model + send yourself |
Competitor capabilities change — we re-audit these tables regularly. Spot something out of date? Tell us and we'll fix it.
One signed JSON object with a normalized auth block and signed attachment URLs — instead of an unsigned form you guard yourself and a trust verdict you grep out of raw headers.
POST /your-webhook
Content-Type: application/x-www-form-urlencoded
from_email=ada@example.com
from_name=Ada
env_from=ada@example.com
env_to_list=agent@myapp.ai
to_list=agent@myapp.ai
subject=Re: invoice #1042
body_text=Looks good — approved!
body_html=<p>Looks good — approved!</p>
header_list=…raw headers; dig out Authentication-Results yourself…
att1_name=po.pdf
att1_content=…inline base64…
# no signature to verify, no spf/dkim/dmarc/spam field 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=…" }
]
} Elastic Email wins on raw send price for high outbound volume; MailKite includes inbound free and never bills per domain. Confirm current numbers on each pricing page before you commit.
Swap the MX record off mx.inbound.elasticemail.com and DNS-verify the domain (MX to receive, SPF + DKIM to send). No Pro plan or sandbox wait to receive.
Delete the urlencoded middleware and the header_list regex. Read the JSON body directly: event.from.address, event.subject, event.text, and event.auth for the trust verdict.
Check x-mailkite-signature with verifyWebhook(), then reply through mk.send({ inReplyTo }) — threading resolves for you. Keep bulk sending on Elastic Email for the price if you like; they're not exclusive.
Yes. Its Inbound Routing points your MX at mx.inbound.elasticemail.com, parses the message, and POSTs the fields (from_email, subject, body_text, body_html, header_list, att1_content, and more) to a URL you configure. MailKite delivers the same message as one signed email.received JSON event with a normalized auth block.
No. There's no SPF, DKIM, DMARC, or spam field in the POST. The only authentication signal is whatever an upstream relay stamped into the raw header_list, which you'd string-parse yourself. MailKite normalizes it into auth: { spf, dkim, dmarc, spam } at the edge.
No. Inbound Email Processing is gated to the Pro plans (Email API Pro is $49/mo at the time of writing), not the free or Starter tiers, and inbound draws from your sending allowance. MailKite's free tier of 3,000 messages/month covers inbound and outbound with no per-domain fee. Confirm current numbers on each pricing page before you commit.
The Elastic Email 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.