A receive email API for developers: point your domain's MX at MailKite and every inbound message lands at your endpoint as signed JSON — sender, subject, body, auth verdicts, attachments — with SDKs for the language you already use.
A receive email API is an HTTP interface that delivers incoming email to your application as structured data. Instead of running a mail server and parsing MIME, you point a domain's MX records at the API provider and every message is parsed, authenticated, and POSTed to your endpoint as JSON — signed so you can verify it before your handler runs.
The same loop in every SDK: read the raw body, verify the signature, act on the JSON.
import { verifyWebhook } from "mailkite"; // npm install mailkite
app.post("/mailkite", express.raw({ type: "*/*" }), async (req, res) => {
const ok = await verifyWebhook(
req.header("x-mailkite-signature"),
req.body, // raw bytes — required to verify
process.env.MAILKITE_WEBHOOK_SECRET,
);
if (!ok) return res.status(401).end();
const email = JSON.parse(req.body);
console.log(email.from.address, "->", email.subject); // ada@example.com -> Re: invoice #1042
res.json({ status: "ok" }); // 2xx acks; MailKite retries anything else
});# pip install mailkite-dev
import hmac, hashlib, os, time
from flask import Flask, request
app = Flask(__name__)
SECRET = os.environ["MAILKITE_WEBHOOK_SECRET"].encode()
@app.post("/mailkite")
def mailkite():
sig = request.headers["x-mailkite-signature"] # t=<ms>,v1=<hex>
parts = dict(p.split("=", 1) for p in sig.split(","))
if abs(time.time() * 1000 - int(parts["t"])) > 300_000: # replay window (t is ms)
return "stale", 401
signed = parts["t"].encode() + b"." + request.get_data()
mac = hmac.new(SECRET, signed, hashlib.sha256).hexdigest()
if not hmac.compare_digest(mac, parts["v1"]): # constant-time
return "bad signature", 401
email = request.get_json()
print(email["from"]["address"], email["subject"])
return {"status": "ok"}<?php // composer require mailkite/mailkite (Laravel route)
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
Route::post('/mailkite', function (Request $request) {
$sig = $request->header('x-mailkite-signature'); // t=<ts>,v1=<hex>
parse_str(str_replace(',', '&', $sig), $parts);
if (abs(time() - (int) $parts['t']) > 300) return response('stale', 401);
$body = $request->getContent(); // raw body
$mac = hash_hmac('sha256', $parts['t'] . '.' . $body, env('MAILKITE_WEBHOOK_SECRET'));
if (!hash_equals($mac, $parts['v1'])) return response('bad signature', 401);
$email = json_decode($body, true);
logger($email['from']['address'] . ' -> ' . $email['subject']);
return response()->json(['status' => 'ok']);
}); Headers, text and HTML, threading, SPF/DKIM/DMARC results, and signed attachment URLs — all broken out for you.
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", "name": "Ada Lovelace" },
"to": [{ "address": "support@myapp.ai", "name": "Support" }],
"subject": "Re: invoice #1042",
"text": "Looks good — approved!",
"html": "<p>Looks good — approved!</p>",
"threadId": "<a1b2c3@mail.example.com>",
"receivedAt": 1785196800000,
"receivedAtIso": "2026-07-28T00:00:00.000Z",
"auth": { "spf": "pass", "dkim": "pass", "dmarc": "pass", "spam": "ham" },
"attachments": [
{
"id": "msg_2Hk9…:0",
"filename": "po.pdf",
"contentType": "application/pdf",
"size": 18213,
"url": "https://api.mailkite.dev/att/2Hk9…/0?exp=…&sig=…"
}
]
} Add your domain and update its MX records. We verify DNS and activate inbound in seconds — no mail server to provision.
Tell MailKite where to POST. Any HTTPS endpoint works — an Express route, a Flask view, a Laravel controller, a Cloudflare Worker.
Receive the signed JSON, call verifyWebhook() (or the equivalent one-liner), and act on the parsed event. That's the whole receive loop.
Node, Python, PHP, Go, Ruby, Java, .NET, and Rust — with a local verifyWebhook() helper in each. Receive email in the language your app already speaks.
The SDK's verifyWebhook(signature, body, secret) handles the HMAC-SHA256 check and the timestamp replay window. No crypto to hand-wire, no timing bugs to write.
Every delivery carries x-mailkite-signature (t=…,v1=…). You can trust the payload is authentic and fresh before your handler reads a single field.
Received messages are stored and queryable through the messages API and the MCP server. Fetch history, backfill a missed event, or let an agent read the inbox.
threadId resolves In-Reply-To and References for you. Group replies into conversations without parsing RFC 5322 headers yourself.
Point MX records at MailKite for as many domains and products as you ship. No per-domain charge, no tier gating on receiving.
Yes. MailKite is a receive email API: point your domain's MX records at MailKite and every inbound message is parsed and delivered to your application as a signed JSON payload, with stored messages readable back through the messages API and MCP server.
Each request carries an x-mailkite-signature header in the form t=<timestamp>,v1=<hex>. Compute HMAC-SHA256 with your webhook secret over the string "<timestamp>.<raw_body>" and compare the hex digest to v1 (with a replay-window check on the timestamp). The Node SDK ships verifyWebhook(signature, body, secret) so you can do it in one call.
Yes. Received messages are stored and queryable through the messages API (list and get) and through MailKite's MCP server, so an AI agent or your own code can fetch history, backfill, or replay an event without holding state on your side.
Node, Python, PHP, Go, Ruby, Java, .NET, and Rust, plus a local verifyWebhook helper in each. Install with npm install mailkite, pip install mailkite-dev, composer require mailkite/mailkite, or the equivalent for your language.
IMAP is a mailbox protocol your code polls and then parses MIME from. A receive email API pushes a pre-parsed JSON payload to your endpoint the moment a message lands — no polling loop, no MIME parser, no open mailbox connection. MailKite also signs every delivery so you can trust it before your handler runs.
Point a domain, drop in a webhook URL, verify your first inbound email. Unlimited domains, no credit card, SDKs in your language.