ZM vs MailKite logo
Alternative to ZeptoMail

Send and receive in one provider — no Zoho Mail and IMAP bolted on to read a reply.

ZeptoMail is Zoho's transactional sending service — cheap, disciplined, and genuinely good at outbound. But it never receives mail, so the moment an agent or app has to read a login code or a reply you bolt on a Zoho Mail mailbox and poll it over IMAP: two providers, two credentials, MIME parsing on your side. MailKite (which we build) does both legs in one API, delivering inbound as parsed JSON.

A fair take on ZeptoMail

For pure outbound, ZeptoMail is a strong, cheap leg: prepaid credits with no monthly floor, a deliberately transactional-only shared IP pool that keeps one-to-one mail landing, and both a REST endpoint and an SMTP relay. If your agent only ever speaks and never listens, it's a good choice.

How it works

ZeptoMail vs MailKite, in one diagram

ZM ZeptoMail (send-only) + Zoho Mail for the inbox sender Zoho Maila real mailbox IMAP pollfetch + parse MIME your agent ZeptoMailsend only Two providers, two credentials. ZeptoMail is only the send box on the right; the whole read half (mailbox, IMAP, MIME parsing, dedupe, SPF/DKIM checks) is yours to run. MailKite sender MX edgeparse + auth JSON webhooksigned, retried your agent mk.send() One provider does both legs. The agent below is the whole "your app" integration.
Why teams switch

What MailKite does differently

One provider does both legs

ZeptoMail is send-only, so to let an agent read anything you add a Zoho Mail mailbox and poll it over IMAP — a second product, a second login. MailKite receives and sends under one account with a shared quota.

Inbound arrives parsed, not as MIME

No IMAP poll loop to babysit, no simpleParser, no \Seen flag to set atomically. MailKite decodes at its MX edge and POSTs one JSON object: text, HTML, resolved threadId, and signed attachment URLs.

Trust signals in the payload

ZeptoMail's inbound path (Zoho Mail over IMAP) hands you raw headers to verify yourself. MailKite includes an auth block — spf, dkim, dmarc, spam — on every received event, which matters when an email is untrusted agent input.

Unlimited domains, free

Run every product, client, and alias from one account at no per-domain cost — and the free tier is ongoing (3,000 msgs/mo in + out), not a short-validity trial credit.

Side by side

MailKite vs ZeptoMail

MailKite ZeptoMail
Send (API + SMTP) Send API + SMTP submission edge REST + SMTP relay, transactional-only
Inbound / receive Yes — parsed JSON webhook None — send-only service
Read a verification code / reply It's in the email.received event Bolt on Zoho Mail, poll IMAP
Providers to run an agent inbox One Two (ZeptoMail out + Zoho Mail in)
Inbound trust signal Structured auth block in payload Derive SPF/DKIM/DMARC yourself
Threaded reply from sent address inReplyTo, reply from event.to[0] Set headers yourself
Per-domain fees None — unlimited domains None (credits by volume)
MCP server + Claude Code plugin Yes None

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

Two providers, two credentials, and the whole decode-and-verify step on your side — versus one signed JSON POST with body, threading, and auth already resolved.

ZeptoMail send + Zoho Mail IMAP (the two-provider inbox)
http
// OUT — ZeptoMail send. Zoho-enczapikey token, nested to[].email_address.
await fetch("https://api.zeptomail.com/v1.1/email", {
method: "POST",
headers: { Authorization: `Zoho-enczapikey ${ZEPTO_SEND_TOKEN}` },
body: JSON.stringify({
from: { address: "agent@yourco.dev" },
to: [{ email_address: { address: replyTo } }],
subject: `Re: ${subject}`,
htmlbody: answer.html, // no inReplyTo/threading helper
}),
});

// IN — ZeptoMail can't receive. Bolt on Zoho Mail, poll over IMAP:
const imap = new ImapFlow({
host: "imap.zoho.com", port: 993, secure: true,
auth: { user: "agent@yourco.dev", pass: ZOHO_APP_PASSWORD },
});
await imap.connect();
await imap.mailboxOpen("INBOX");
for await (const msg of imap.fetch({ seen: false }, { source: true })) {
const mail = await simpleParser(msg.source); // MIME → fields is yours
// dedupe, mark \Seen atomically, verify SPF/DKIM/DMARC: also yours
}
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

ZeptoMail

  • Prepaid credits, one credit sends 10,000 emails
  • No monthly floor — quiet month, pay nothing
  • Free trial credit; an inbox means also paying for Zoho Mail

For pure outbound at volume ZeptoMail's credits are very cheap. But a receive-and-reply agent means also running Zoho Mail plus your own IMAP pipeline, so total cost and setup usually favor one provider.

See full MailKite pricing →

Switch in an afternoon

Moving from ZeptoMail

  1. 1

    Keep sending, add receiving

    Point your domain's MX at MailKite to receive, and verify SPF + DKIM to send. You can retire the Zoho Mail mailbox and IMAP poller you bolted on just to read replies.

  2. 2

    Delete the poll loop

    Drop ImapFlow, simpleParser, the \Seen bookkeeping, and the SPF/DKIM checks. Set your webhook URL and read event.from.address, event.subject, event.text, event.auth.

  3. 3

    Reply through the same API

    Swap the ZeptoMail send call for mk.send() — one account, one token. Use inReplyTo and reply from event.to[0] so the thread stays intact.

Questions

Does ZeptoMail support inbound (receiving) email?

No. ZeptoMail is Zoho's transactional sending service — no inbound webhook, no inbound parse, no IMAP. Its webhooks report events on mail you already sent (bounces, opens, clicks, complaints), not messages arriving. To read mail you add a separate product, Zoho Mail, over IMAP.

What's the difference between ZeptoMail and Zoho Mail?

ZeptoMail sends transactional email (API + SMTP) and never receives. Zoho Mail is the actual mailbox product with IMAP/POP/SMTP. An agent that must both send and read on Zoho ends up running both, with two logins and two credentials. MailKite does both halves under one account.

Is ZeptoMail cheaper than MailKite?

For pure outbound at volume, ZeptoMail's prepaid credits (one credit sends 10,000 emails, no monthly floor) are very cheap. But an agent inbox on ZeptoMail means also paying for and running Zoho Mail plus your own IMAP pipeline. MailKite starts free at 3,000 messages/mo in and out with no per-domain fee, so a receive-and-reply workload usually favors one provider.

Go deeper

The ZeptoMail alternative for AI agents →

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

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

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