Unlimited domains, 3K emails/month, free. Receive email as a webhook, send with one API. No credit card required.
Switched from SendGrid, inbox placement went from ~92% to ~99% in two weeks.
Mark — AdRender.app
The same address that receives can send. One endpoint, one key — transactional mail, replies, and broadcasts go out over your own authenticated domain, built on Cloudflare’s edge.
No code to add? Point WordPress, a CRM, or any app that speaks SMTP at our relay →
import { MailKite } from "mailkite";
const mk = new MailKite(process.env.MAILKITE_API_KEY);
const { id, status } = await mk.send({
from: "hello@myapp.ai",
to: "ada@example.com",
subject: "Your invoice #1042",
html: "<p>Thanks! Receipt attached.</p>",
});POST /v1/send HTTP/1.1
Host: api.mailkite.dev
Authorization: Bearer mk_live_3a9f…
Content-Type: application/json
{
"from": "hello@myapp.ai",
"to": "ada@example.com",
"subject": "Your invoice #1042",
"html": "<p>Thanks! Receipt attached.</p>",
"attachments": [
{ "filename": "receipt.pdf", "url": "https://…" }
]
}
← 202 Accepted
{ "id": "msg_2Hk9…", "status": "queued" }import os
from mailkite import MailKite
mk = MailKite(os.environ["MAILKITE_API_KEY"])
res = mk.send({
"from": "hello@myapp.ai",
"to": "ada@example.com",
"subject": "Your invoice #1042",
"html": "<p>Thanks! Receipt attached.</p>",
})<?php
$mk = new \MailKite\Client(getenv('MAILKITE_API_KEY'));
$res = $mk->send([
'from' => 'hello@myapp.ai',
'to' => 'ada@example.com',
'subject' => 'Your invoice #1042',
'html' => '<p>Thanks! Receipt attached.</p>',
]);MailKite mk = new MailKite(System.getenv("MAILKITE_API_KEY"));
Object res = mk.send(Map.of(
"from", "hello@myapp.ai",
"to", "ada@example.com",
"subject", "Your invoice #1042",
"html", "<p>Thanks! Receipt attached.</p>"
));mk := mailkite.New(os.Getenv("MAILKITE_API_KEY"))
res, err := mk.Send(mailkite.Message{
From: "hello@myapp.ai",
To: "ada@example.com",
Subject: "Your invoice #1042",
HTML: "<p>Thanks! Receipt attached.</p>",
})require "mailkite"
mk = Mailkite::Client.new(ENV["MAILKITE_API_KEY"])
res = mk.send(
"from" => "hello@myapp.ai",
"to" => "ada@example.com",
"subject" => "Your invoice #1042",
"html" => "<p>Thanks! Receipt attached.</p>"
)curl https://api.mailkite.dev/v1/send \
-H "Authorization: Bearer $MAILKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@myapp.ai",
"to": "ada@example.com",
"subject": "Your invoice #1042",
"html": "<p>Thanks! Receipt attached.</p>"
}' This is exactly what hits your endpoint the moment an email arrives — no MIME wrangling, no encoding surprises.
import express from "express";
import { MailKite } from "mailkite";
const app = express();
app.use(express.json());
app.post("/hooks/mailkite", (req, res) => {
// Verify the signature in production — see /docs/webhook-security
const email = req.body; // { from, subject, text, html, attachments }
res.json(MailKite.replyOk()); // {"status":"ok"}
});POST /your/webhook HTTP/1.1
Content-Type: application/json
{
"from": "ada@example.com",
"to": "hello@myapp.ai",
"subject": "Re: invoice #1042",
"text": "Looks good — approved!",
"html": "<p>Looks good — approved!</p>",
"attachments": [
{
"id": "msg_8f3a...:0",
"filename": "po.pdf",
"contentType": "application/pdf",
"size": 18213,
"url": "https://api.mailkite.dev/att/9f86d0c2"
}
],
"messageId": "<a1b2c3@mail.example.com>",
"receivedAt": "2026-06-19T17:42:10Z"
}from flask import Flask, request
from mailkite import reply_ok
app = Flask(__name__)
@app.post("/hooks/mailkite")
def hook():
# Verify the signature in production — see /docs/webhook-security
email = request.get_json() # { "from", "subject", "text", ... }
return reply_ok(), 200, {"content-type": "application/json"}<?php
$mk = new \MailKite\Client("");
// Verify the signature in production — see /docs/webhook-security
$email = json_decode(file_get_contents("php://input"), true);
header("content-type: application/json");
echo $mk->replyOk(); // {"status":"ok"}// Spring Boot
@PostMapping(value = "/hooks/mailkite", produces = "application/json")
public String mailkite(@RequestBody Map<String, Object> email) {
MailKite mk = new MailKite("");
// Verify the signature in production — see /docs/webhook-security
return mk.replyOk(); // {"status":"ok"}
}http.HandleFunc("/hooks/mailkite", func(w http.ResponseWriter, r *http.Request) {
// Verify the signature in production — see /docs/webhook-security
var email map[string]any
json.NewDecoder(r.Body).Decode(&email)
w.Header().Set("content-type", "application/json")
w.Write([]byte(mailkite.ReplyOk())) // {"status":"ok"}
})require "sinatra"
require "json"
require "mailkite"
post "/hooks/mailkite" do
# Verify the signature in production — see /docs/webhook-security
email = JSON.parse(request.body.read)
content_type :json
Mailkite.reply_ok # {"status":"ok"}
end Transactional, broadcast, or a brand-new domain — MailKite reads each message and routes it through the provider most likely to land it: Amazon SES, Cloudflare, or Postmark. Warm pools on day one, and an automatic reroute if a network degrades. You never pick a provider or babysit an IP.
MailKite routes each message through the provider most likely to land it — and reroutes automatically if one degrades.
Add as many domains as you need. Each gets its own inbound routes, webhook targets, and sending identity. No per-domain charges, no limits.
Send and receive up to 3,000 emails per month on the free tier. Enough for most side projects, MVPs, and early-stage products.
Every incoming email parsed into clean JSON and POSTed to your endpoint. No multipart form decoding, no MIME assembly.
Transactional email via REST API or SDK. DKIM signing, deliverability tracking, and bounce handling built in.
Sign up, get an API key, start sending. No payment info required. Upgrade only when you need to.
Give your AI agents their own inbox. Native MCP support means agents can read, send, and manage email without custom glue code.
| MailKite | SendGrid | Mailgun | |
|---|---|---|---|
| Domains | Unlimited, free | 1 (free tier) | 1 (free tier) |
| Emails/month | 3,000 | 100/day (~3,000) | 5,000 |
| Inbound email | Webhook, clean JSON | Multipart parse | Inbound routes |
| Outbound sends | 3K/month included | 100/day limit | 5,000/month |
| SDKs | 8 languages | 8 languages | 7 languages |
| MCP / AI agents | Native support | Not available | Not available |
| Credit card required | No | No (but limited) | No (but limited) |
Still deciding? Get your API key and try it yourself — no credit card.
Yes. Unlimited domains, 3K emails per month, no credit card, no daily send cap. You pay only when volume grows past the free threshold.
Unlimited domains, 3K emails per month, inbound email as webhook, outbound send API, SDKs for every language, HMAC-signed payloads, built-in threading, and full dashboard access. No feature gating.
SendGrid's free tier is limited to 100 emails/day and 1 domain. MailKite gives you unlimited domains and 3K emails/month with no daily cap — and MCP support for AI agents that SendGrid doesn't offer.
MailKite uses graceful overage — your service never stops. You're notified when approaching limits and can upgrade with one click. No surprise cutoffs, no silent suspensions.
Unlimited domains, 3K emails/month, free. No credit card. Under 5 minutes to first email.
Free up to 3,000 emails/mo. $20/mo when you scale — no credit card.
Get your API key — unlimited domains, 3K emails/mo, free.
Get started free