Receive email as a webhook. Send with one API. Manage unlimited domains. Built for multi-product SaaS teams and the AI agents they build.
Free up to 3,000 emails/mo. $20/mo when you scale — no credit card.
Switched from SendGrid, inbox placement went from ~92% to ~99% in two weeks.
Mark — AdRender.app
Point MX records at MailKite. Every incoming message is parsed into clean JSON and POSTed to your endpoint. No mail server, no MIME parsing.
Inbound email APISend email with one API call. SDKs for every language. Deliverability built in — DKIM, SPF, feedback loops handled for you.
Send email with one APIAdd as many domains as you need. Each domain gets its own inbound routes, webhook targets, and sending identity. No per-domain charges.
Free transactional emailGive every agent its own inbox via MCP. Agents receive, parse, and reply to email — with human supervision from the dashboard.
MCP-native email for agentsFor apps that speak SMTP: relay outbound mail through MailKite with full DKIM signing and deliverability tracking.
SMTP relayRead your inbox in your framework. MIT-licensed webmail client drops into Next.js, Astro, Nuxt, or SvelteKit.
Webmail for your domainThe 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.
Instant API key — no waiting, no approval. Start building in under 5 minutes.
Point MX records at MailKite. We verify DNS and activate the domain automatically.
Register a webhook for inbound, or fire the send API for outbound. Clean JSON in, clean API out.
Ship 10+ domains without rebuilding email plumbing per product. One platform, one API key, unlimited domains.
Reply-by-email, support inboxes, inbound parsing, verification codes — clean JSON webhooks, not a wiring project.
Agents with their own inbox, two-way threads, and MCP integration. Human supervision built in.
MailKite is an inbound-first email platform for developers. Receive email as a webhook, send with one API, manage unlimited domains. Built for teams shipping multiple products and the AI agents they build.
SendGrid and Postmark are send-first platforms with inbound bolted on. MailKite is inbound-first: every incoming email becomes a clean JSON webhook. We also include unlimited free domains, graceful overage, and MCP-native agent support.
Yes. MailKite is free on unlimited domains. No credit card required. You pay only when you need higher volume or premium features.
Official SDKs for Node.js, Python, Go, Ruby, PHP, Java, .NET, and Rust. Plus an MCP server for AI agents and an SMTP relay for legacy apps.
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.
Email infrastructure — unlimited domains, 3K emails/mo, free.
Get your API key