Docs
Use your own domain
Sending agent mail from a domain you control means publishing DNS records yourself. This application never writes, edits or removes a record on your behalf — it tells you the exact values and then checks what is actually published.
A platform address on agents.emailforagents.ai works with no DNS at all and is the
right place to start; this page is for when an
agent inbox needs to be at your own domain instead. If you have
not created any inbox yet, do the quickstart first.
What you need first
- A live project. Test projects cannot attach domains at all; the attempt returns
test_mode_unsupported, and test addresses stay on non-routable.mail.invalidhosts. - An eligible paid subscription. Attaching a domain without one returns
payment_required. Each plan has a custom-domain count; exceeding it returnsquota_exceeded. - Access to your DNS zone, and a change window if the domain already carries mail.
Paid checkout is currently disabled, so the paid subscription this feature requires cannot be bought today. Domain setup does not route around that requirement. Until checkout ships, the usable path is a platform address. See pricing.
Start with a dedicated subdomain
Use a hostname such as agents.example.com rather than your company's root domain.
Three reasons, in order of how much they will cost you if you ignore them:
- Receiving mail at a hostname means publishing MX there. Publish MX at a hostname that already receives employee mail and you redirect that mail. A subdomain has no existing MX to break.
- Sending reputation stays separated. An agent that gets a bounce or a complaint does not drag your primary domain's reputation with it.
- Revocation is a zone edit. Removing a subdomain's records is a contained change you can make in a minute.
Preview the exact hostname in Domains before attaching it. The preview resolves DNS to see
whether MX already exists; it does not attach a provider domain and it changes nothing. If MX
is found, keep the default preserve_existing mode: that enables sending
verification for the hostname and leaves receiving disabled, so nothing you publish can
interrupt delivery to existing mailboxes. The preview will also suggest
agents.<your domain> as the safer target.
Choose migrate only when you genuinely intend to move all receiving mail
at that hostname. It records your consent; it still makes no DNS changes.
The records, and the order they appear in
You do not get every record up front, and that is deliberate: the provider-issued sending and receiving values are only created after ownership is proven. Asking you to publish them earlier would mean handing out mail-routing records for a hostname nobody had demonstrated control of.
| Stage | Record | Purpose | Where it comes from |
|---|---|---|---|
| 1 | TXT at _efa-challenge.<domain> | Ownership |
Issued immediately on attach. Value is efa-ownership= plus a token unique to
this attachment.
|
| 2 | TXT at the domain — SPF | Sending | Issued by the mail provider after ownership verifies. |
| 2 | DKIM record at the host the provider names | Sending | Issued by the provider after ownership verifies. Publish the type, host and value exactly as displayed; do not retype the key. |
| 3 | MX at the domain, with a priority | Receiving | Issued by the provider after ownership verifies, and only when receiving is not held back by existing MX. |
Type TXT
Host _efa-challenge.agents.example.com (relative: _efa-challenge)
Value efa-ownership=efa_9c41a7...
The console shows both the fully-qualified host and the relative host, because DNS providers
disagree about which one they want — some expect
_efa-challenge.agents.example.com, others expect _efa-challenge with
the zone appended for you. Publishing both forms creates a record at
_efa-challenge.agents.example.com.agents.example.com, which is the single most
common reason verification does not complete.
Each record carries its own status while you work:
| Record status | Meaning |
|---|---|
pending | Published value expected; not yet observed. |
found | The expected value was observed in DNS. |
missing | Nothing at all was found at that host. |
mismatch | Something is there, but it is not the expected value. Usually a truncated or re-wrapped TXT string. |
awaiting_provider | The value does not exist yet. It appears after ownership verifies. |
blocked_existing_mx | Receiving here would replace existing MX, and you chose to preserve it. |
Do not replace an existing root SPF record with a value intended for a sending
subdomain. SPF is per-hostname: the record shown for
agents.example.com belongs at agents.example.com. Overwriting the
SPF at example.com with it can stop your existing mail authenticating. A
hostname should also have exactly one SPF TXT record — two is a permanent error in the
specification, not a merge.
Verifying ownership
- Attach the domain. Copy its unique
_efa-challengeTXT record into your DNS provider. - Leave the TXT record in place — permanently — and choose Check verification and provider setup.
- Once ownership is confirmed, the console displays the exact SPF, DKIM and receiving records returned by the mail provider, including MX priority.
- Publish those records at their displayed hosts.
- Check again after DNS propagates. Each check reads DNS live; it never writes.
Only one verification check runs at a time per domain — a second concurrent request returns
temporarily_unavailable rather than racing the first. An explicit check can also
ask the provider to re-run its own verification, at most once a minute. Between your checks,
the system re-reads DNS in the background roughly every five minutes, so a record you remove
later will be noticed.
Three statuses, not one
Ownership, sending and receiving are tracked separately because they can genuinely disagree: a domain can be authenticated for sending while receiving nothing.
| Status | Values | What it gates |
|---|---|---|
ownership_status | pending, verified, lost | Everything. Losing it disables routing for every inbox on the domain. |
sending_status | disabled, pending, ready | Whether the provider has verified SPF and DKIM for the hostname. |
receiving_status | disabled, pending, ready | Whether mail addressed to the hostname arrives here. |
Receiving readiness requires the MX set at the hostname to match the provider's set
exactly — same hosts, same values, same priorities, and no extras. An additional MX at
any priority is a real routing path to somewhere else, so readiness stays
pending until it is removed. This is the check that most often surprises people
who left an old record behind.
Creating an address
Attaching a domain does not create an inbox. When the statuses you need are ready, go back to Inboxes, select the same live project, choose the custom hostname under Address domain, and give the inbox a display name and optional local part.
Then prove both directions before you hand it to an agent: send a message to the new address from a mailbox you control, and have the inbox reply. A ready status is evidence that the configuration is correct. It is not a promise about whether a particular recipient's provider will place your mail in their inbox, and nothing on this page can be.
Using the API
POST /v1/projects/{project_id}/domains
{
"domain": "agents.example.com",
"receiving_mode": "preserve_existing"
} receiving_mode defaults to preserve_existing. Supply
"receiving_mode": "migrate" to record an intentional migration of all mail at that
hostname; it changes what the wizard will offer, not your DNS.
| Call | Does |
|---|---|
POST /v1/projects/{project_id}/domains/preview | Resolves DNS and returns the record plan. Nothing is stored. |
POST /v1/projects/{project_id}/domains | Attaches the domain and issues the ownership token. |
GET /v1/projects/{project_id}/domains/{domain_id} | Returns every record with its host, expected value, priority and status. |
POST /v1/projects/{project_id}/domains/{domain_id}/verify | Re-reads DNS and re-checks provider setup. |
POST /v1/projects/{project_id}/inboxes | With domain_id and an optional local_part, creates the address. |
The domain must be a hostname, not a URL or a mailbox: agents.example.com, never
https://agents.example.com or ada@example.com. Bare IP addresses and
localhost are refused. Anything else returns invalid_request with a
message saying so. Every response carries mutates_customer_dns: false, which is
not decoration — it is the invariant this whole flow is built around.
When setup needs attention
Symptom What to do Ownership lost
The challenge TXT is gone or changed. Restore the exact value. Sending and routing stop
until verification succeeds again, and a later owner of the domain gets a new token
rather than inheriting yours.
Ownership record shows mismatch
Something is published but not the expected string. Check for added quotes, a split TXT
string, or the doubled-host mistake above.
Receiving stuck at pending
Compare host, value and priority exactly, and remove every MX that is not in the
provider's set. An extra record keeps receiving pending.
Sending stuck at pending
The provider has not yet verified SPF and DKIM. Confirm both are at the hostname the
console names, then re-check. DNS caches can hold an old negative answer for a while.
Provider status unknown or failed
Do not repeatedly delete and re-attach. Provider-side creation may have completed despite
a timeout, and re-attaching can leave two claims on one hostname. Custody in that state
needs support review.
Inbox paused right after creation
The address is reserved while a provisioning result is reconciled. Creating it again will
not silently allocate a second address.