Domains & DNS
A domain is what lets MailKite receive mail for you and send authenticated mail on your behalf. You can add unlimited domains — one per product, per environment, per tenant — at no per-domain cost.
Add a domain
Add any domain or subdomain you control. Subdomains like
mail.myapp.ai or a free myapp.mailkite.dev are a great
fit and keep your root domain's reputation separate.
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" }'
The response includes the DNS records to publish. New domains start in
pending and move to verified once DNS resolves.
Register a new domain
Don't have a domain yet? Register one from the dashboard and we'll set it up for you —
you're the legal owner. Search a name (we check popular TLDs like
.com, .ai, .io, .dev), pick an
available one, and we register it in your name and provision the mail DNS automatically, so it's
usually verified the moment it's registered — no DNS to paste.
Registration requires a card on file (add it in Billing). The price shown is what you pay — the registrar's cost plus payment processing and a small service fee. Domain registrations are non-refundable. Your card is also used for usage-based billing (below).
Free MailKite subdomain
The fastest start: claim a free MailKite subdomain — a your-app.<base>
host on a zone we run. We set up the DNS for you, so it works the instant you claim it —
no registrar, no card, no DNS. Great for trying MailKite or for projects that don't need a
custom domain.
Claim one from the dashboard, with mailkite domains claim your-app, or over the
API — see automated onboarding. Which zone
new subdomains are handed out under changes over time, and more than one may be offered, so
read the current base from the API rather than hard-coding a hostname. Subdomains
claimed on a retired zone keep working.
The DNS records
Add these four records at your DNS provider. Names are shown for
myapp.ai — substitute your own domain.
| Type | Name | Value | Purpose |
|---|---|---|---|
MX | myapp.ai | mx.mailkite.dev (priority 10) | Routes inbound mail to MailKite. Required to receive. |
TXT | myapp.ai | v=spf1 include:mailkite.dev ~all | SPF — authorizes MailKite to send for the domain. |
TXT | mailkite._domainkey.myapp.ai | v=DKIM1; k=rsa; p=… | DKIM — signs outbound so it passes authentication. |
TXT | _dmarc.myapp.ai | v=DMARC1; p=none; | DMARC — alignment policy. Start at none, tighten later. |
The exact values — including your per-domain DKIM public key — are shown in the dashboard and returned fromPOST /api/domainsandGET /api/domains/:id. Always copy from there rather than this page.
Not sure where these go at your DNS host? Follow the step-by-step DNS setup guides for GoDaddy, Cloudflare, Namecheap, Squarespace Domains, and Amazon Route 53.
Verify
After publishing the records, trigger a check. MailKite looks up your records over DNS-over-HTTPS and records the result.
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>" {
"status": "verified",
"checks": { "mx": true, "spf": true, "dkim": true, "dmarc": true },
"checkedAt": 1750000000000
}
A domain becomes verified as soon as MX resolves
to mx.mailkite.dev — that's the record that enables receiving.
SPF, DKIM, and DMARC are reported separately and monitored on an ongoing
basis so you know if a record drifts. DNS can take anywhere from a minute to a
few hours to propagate; re-run verification until everything is green.
Addresses on a domain
Once verified, every address on the domain receives. By default a
catch-all routes all mail (*@myapp.ai) to the
webhook you set for the domain. To split traffic — say, send
support@ to one endpoint and billing@ to another —
create per-address routes. This is what lets you
give every agent, task, or tenant its own address with no extra setup.
Removing a domain
Dashboard → Domains → myapp.ai
Click [ Remove domain ] → confirmRemove the domain myapp.ai from my accountawait mk.deleteDomain("dom_…");mk.deleteDomain("dom_…")$mk->deleteDomain('dom_…');mk.deleteDomain("dom_…");_, err := mk.DeleteDomain("dom_…")mk.deleteDomain("dom_…")curl -X DELETE https://api.mailkite.dev/api/domains/dom_… \
-H "Authorization: Bearer <session-token>" Deleting a domain stops inbound routing for it. Remove the MX record at your DNS provider too if you no longer want mail attempted for the domain.
Next: receive your first message, or set up authentication for the API.