Quickstart
In a few minutes you'll have a live address that receives mail at your webhook and sends with one API call. Every step works three ways — click through the dashboard, ask the AI assistant, or call the API. Pick a tab in any box below and the whole page follows along.
1. Get your API key
Every call below authenticates with one key. Create a free account and grab
your key (mk_live_…) from the dashboard — you'll pass it as
Authorization: Bearer mk_live_… on every request. Nothing here
runs without it.
Signed in — the samples below are filled with your real key.
2. Get a domain
Every address lives on a domain MailKite handles the mail for. You have three ways to get one:
- Bring a domain you already own — use
myapp.aior a subdomain likemail.myapp.ai, then publish the DNS records MailKite gives you (step 2). - Register a new domain — search for one and buy it right inside MailKite; we wire up the DNS automatically, so you can skip step 2.
- Use a free MailKite subdomain — grab
myapp.mailkite.devormyapp.mailn.appand start instantly, with no DNS to configure.
The example below adds myapp.ai. MailKite returns the
DNS records to publish (a registered or free MailKite domain comes
pre-configured).
Dashboard → Domains
Click [ + Add domain ]
Type myapp.ai
Click [ Add ]Add the domain "myapp.ai"const res = await mk.createDomain({ domain: "myapp.ai" });res = mk.createDomain({"domain": "myapp.ai"})$res = $mk->createDomain(['domain' => 'myapp.ai']);Object res = mk.createDomain(Map.of("domain", "myapp.ai"));res, err := mk.CreateDomain(map[string]any{"domain": "myapp.ai"})res = mk.createDomain("domain" => "myapp.ai")curl https://api.mailkite.dev/api/domains \
-H "Authorization: Bearer <session-token>" \
-H "Content-Type: application/json" \
-d '{ "domain": "myapp.ai" }' myapp.ai ● pending
Publish these DNS records:
MX myapp.ai mx.mailkite.dev (priority 10)
TXT myapp.ai v=spf1 include:mailkite.dev ~all
TXT mailkite._domainkey.myapp… v=DKIM1; k=rsa; p=…
TXT _dmarc.myapp.ai v=DMARC1; p=none;
[ Copy all ] [ Verify DNS ]Added myapp.ai — status pending.
Add these DNS records at your provider, then ask me to verify:
• MX → mx.mailkite.dev (priority 10)
• TXT SPF: v=spf1 include:mailkite.dev ~all
• TXT DKIM: mailkite._domainkey → v=DKIM1; k=rsa; p=…
• TXT DMARC: _dmarc → v=DMARC1; p=none;{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
}{
"domain": { "id": "dom_…", "domain": "myapp.ai", "status": "pending" },
"dns": [
{ "type": "MX", "name": "myapp.ai", "value": "mx.mailkite.dev", "priority": 10 },
{ "type": "TXT", "name": "myapp.ai", "value": "v=spf1 include:mailkite.dev ~all" },
{ "type": "TXT", "name": "mailkite._domainkey.myapp.ai", "value": "v=DKIM1; k=rsa; p=…" },
{ "type": "TXT", "name": "_dmarc.myapp.ai", "value": "v=DMARC1; p=none;" }
]
} See Domains & DNS for registering, bringing your own domain, and the free subdomains in full.
3. Publish the DNS records
Add the four records to your DNS provider. MX enables receiving; SPF and DKIM let your outbound mail pass authentication and land in the inbox; DMARC ties it together. Then verify:
Dashboard → Domains → myapp.ai
Click [ Verify DNS ]Verify the DNS for myapp.aiawait mk.verifyDomain("dom_…");mk.verifyDomain("dom_…")$mk->verifyDomain('dom_…');mk.verifyDomain("dom_…");_, err := mk.VerifyDomain("dom_…")mk.verifyDomain("dom_…")curl -X POST https://api.mailkite.dev/api/domains/dom_…/verify \
-H "Authorization: Bearer <session-token>"
A domain flips to verified as soon as its MX record resolves to
mx.mailkite.dev. We keep checking the rest in the background.
4. Point a webhook
Tell MailKite where to POST inbound mail. Any HTTPS endpoint
works (and http://localhost while developing).
Dashboard → Domains → myapp.ai → Webhook
Paste https://myapp.ai/hooks/mailkite
Click [ Save ]Send inbound mail for myapp.ai to https://myapp.ai/hooks/mailkiteawait mk.setWebhook("dom_…", { url: "https://myapp.ai/hooks/mailkite" });mk.setWebhook("dom_…", {"url": "https://myapp.ai/hooks/mailkite"})$mk->setWebhook('dom_…', ['url' => 'https://myapp.ai/hooks/mailkite']);mk.setWebhook("dom_…", Map.of("url", "https://myapp.ai/hooks/mailkite"));_, err := mk.SetWebhook("dom_…", map[string]any{"url": "https://myapp.ai/hooks/mailkite"})mk.setWebhook("dom_…", "url" => "https://myapp.ai/hooks/mailkite")curl -X PUT https://api.mailkite.dev/api/domains/dom_…/webhook \
-H "Authorization: Bearer <session-token>" \
-H "Content-Type: application/json" \
-d '{ "url": "https://myapp.ai/hooks/mailkite" }'
Every message to any address on the domain now arrives at your endpoint as
JSON. Fire a test event from the dashboard or with
POST /api/domains/:id/webhook/test, then read
Inbound webhooks to learn the payload — and
verify the signature so you only trust
real events.
5. Send your first email
Use the key from step 1 (mk_live_…) to send. The
from address must be on a verified domain.
Dashboard → Send
From hello@myapp.ai
To ada@example.com
Subject Your invoice #1042
Body Thanks! Receipt attached.
Click [ Send ]Email ada@example.com from hello@myapp.ai
with subject "Your invoice #1042" and body "Thanks! Receipt attached."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>",
});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>"
}'
You'll get back a 202 Accepted with a message id. That's it —
you're sending and receiving over your own authenticated domain, with no mail
server to run.
Next steps
- Inbound webhooks — the full
email.receivedpayload and attachments. - Send API — attachments, HTML + text, and in-thread replies.
- Agent inboxes & MCP — wire email into an AI agent.
- API reference — every endpoint in one place.