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 from the dashboard.
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.<base>on a zone we run and 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 — optional
Only needed if you want to receive mail at this domain. Skip
it if you're just sending. To receive, 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.
Messages → Compose
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.