Domains
Add your own domain to MachineMail for custom inbox addresses and catch-all. Covers DNS records, verification states, DNS host detection, Domain Connect and the zone file.
Inboxes on machinemail.dev work out of the box. Add a custom domain when you want addresses like support@agents.acme.dev, catch-all addresses, or sending that is authenticated as your own domain. Subdomains work the same as apex domains, and keep your main domain’s mail setup untouched.
For a step-by-step walkthrough, see Use a custom domain.
Adding a domain
| Field | Notes |
|---|---|
domain | Required. A hostname. Must not already be registered by any organization. |
inbound_enabled | Default true. When false, the MX record is not required and the domain is send-only. |
catch_all | Default false. Accept mail to any address. See Catch-all. |
catch_all_ttl_seconds | Make catch-all inboxes ephemeral with this TTL. |
feedback_enabled | Default false. Stored for AgentMail compatibility. |
client_id | Idempotency key. |
The response lists the DNS records to publish:
Always publish the records exactly as the API returns them for your domain. The set can differ between domains, for example when sending records are issued per domain, in which case purpose is provider.
DNS records
purpose | What it does | Required |
|---|---|---|
inbound | MX record that routes mail for the domain to MachineMail. | Yes, when inbound_enabled is true. |
spf | Authorises MachineMail to send for the domain. | Yes |
dkim | Public key receivers use to check MachineMail’s signature on your mail. A new 2048-bit key is generated per domain. | Yes |
provider | Extra sending records some domains need. | Yes |
dmarc | A starter DMARC policy. | No. Skip it if you already have DMARC. |
Each record has a status:
Record status | Meaning |
|---|---|
MISSING | Nothing found at that name. |
INVALID | Something is there but it does not match. reason shows what was found. |
VALID | Matches. |
An existing SPF record is fine as long as it contains include:spf.machinemail.dev. Any DMARC record counts as valid.
Verification
verify looks up every record now and returns the updated domain.
Domain status | Meaning |
|---|---|
NOT_STARTED | Added but never verified. |
PENDING | Some required records are still missing. |
INVALID | A required record exists with the wrong value. |
VERIFIED | Every required record is valid. verified_at is set and a domain.verified event fires. |
reason explains what is outstanding, for example "MX agents.acme.dev is missing". It is absent once the domain is verified. The values FAILED and VERIFYING exist in the AgentMail enum but MachineMail does not currently use them.
After the first verify, MachineMail keeps re-checking PENDING and INVALID domains in the background about every 5 minutes, for up to 7 days after the domain was added. A domain in NOT_STARTED is not checked automatically, so call verify once after publishing the records. last_checked_at shows when the last check ran.
Note
You can create inboxes on a domain right after adding it. Mail only arrives once the MX record resolves, and catch-all only works once the domain is VERIFIED. Wait for verification before sending
from the domain; until SPF and DKIM are in place, receivers are likely to reject or junk your mail.
DNS host detection
When you add or verify a domain, MachineMail looks up the zone’s nameservers and recognises common DNS hosts. The domain then carries:
nameservers: the authoritative nameservers it found.dns_provider:cloudflare,route53,google,vercel,namecheap,godaddy,digitalocean,hetzner,porkbunorother.dns_provider_url: a link straight to the zone’s DNS settings at that host, when known.
The dashboard uses these to show an Open in [provider] button on the domain page.
Domain Connect
Domain Connect lets a DNS host add records for you after you approve them in its own UI. Cloudflare, GoDaddy, IONOS and others support it. When it works for your zone, the dashboard shows Add records at [provider], which opens the provider with MachineMail’s records prefilled.
When supported is true, apply_url is a signed link that adds only the records still outstanding. Open it in a browser (a popup of width by height, or a new tab). After you approve, the provider sends you back to the domain page in the dashboard, which runs a verify. The domain object also carries a short domain_connect summary (supported, provider_name, apply_url) from the last check.
reason explains why there is no apply URL:
reason | Meaning |
|---|---|
no_domain_connect | The zone’s DNS host does not support Domain Connect. |
no_sync_flow | The host supports Domain Connect but not the synchronous flow MachineMail uses. |
template_not_supported | The host has not onboarded MachineMail’s template yet. |
records_not_templatable | The domain’s records don’t fit the template. |
already_configured | Every record is already in place. |
provider_error | The host’s Domain Connect API failed. Retried after about 10 minutes. |
not_configured | Domain Connect is turned off. |
Warning
Domain Connect onboarding with DNS providers is still pending. Until MachineMail’s template is published and accepted by each provider, discovery returns template_not_supported (or
records_not_templatable when the records don’t fit the template), and the dashboard falls back to the Open in [provider] console link and the zone file. Add the records by hand in the
meantime.
Zone file
GET /v0/domains/{domain_id}/zone-file returns the records as a BIND zone file (text/plain, downloaded as agents.acme.dev.zone). Many DNS hosts, including Cloudflare, can import it.
Catch-all
With catch_all: true on a verified domain with inbound enabled, mail to any address at the domain is accepted. The first message to a new address creates the inbox with created_by: "catch_all" in the domain’s pod. With catch_all_ttl_seconds set, those inboxes are ephemeral and are deleted after that long without new mail.
The local part must be a valid username (a-z, 0-9 and . _ + -). Mail to invalid local parts is not delivered.
Catch-all is off by default and never applies to the shared machinemail.dev domain.
Updating and deleting
PATCH /v0/domains/{domain_id} accepts catch_all, catch_all_ttl_seconds (null to clear), inbound_enabled and feedback_enabled. Turning inbound_enabled off makes the MX record optional and recomputes the status.
DELETE /v0/domains/{domain_id} removes the domain from MachineMail. Inboxes already created on it are not deleted; delete them separately. Inbox-scoped keys cannot add domains; pod keys see and add domains in their pod only.