Custom domains
Register your own domain, publish its DNS records, verify it, and manage it across its whole lifecycle.
Register a Custom Domain
To use a custom domain email address, you need to be on the Developer plan or above and register it.
A domain whose mail already routes to Google Workspace or Microsoft 365 cannot be registered. In that case, register a dedicated subdomain (like mail.example.com).
If you have registered your apex domain already, you can enable subdomains configuration to create inboxes with addresses on any subdomain without having to register it. See Register a subdomain.
A domain belongs to your organization as a whole, or to one pod when its inboxes should live inside that pod’s isolated set of resources. Pod-owned domains use the same operations through the pod routes: /v0/pods/{pod_id}/domains in the API, client.pods.domains in the SDKs, and pods:domains in the CLI.
Register the domain
You can also do this in the AgentMail Console under Domains.
domain is the only required input.
agentmail domains create --domain "example.com"| Param | Type | What it means |
|---|---|---|
domain | string | The domain or subdomain to register, like example.com or mail.example.com. Needs at least one dot. |
feedback_enabled | boolean | Deliver bounce and complaint notifications to your inboxes as emails, so your agent learns when an address is dead or a recipient marked its mail as spam. Defaults to true. Set false to stop the notification emails. |
subdomains_enabled | boolean | Allow inboxes on any subdomain of this domain. Adds a required wildcard MX record (*.<domain>) to records. Defaults to false. |
tracking_enabled | boolean | Serve open tracking pixels from this domain. Adds a required link.<domain> CNAME record to records, which must be published and verified before track_opens works on a send. Defaults to false. |
client_id | string | Your own idempotency id. Retrying the create with the same client_id returns the already-registered domain instead of an error. |
The response contains a records list with every DNS record to publish:
{
"domain_id": "example.com",
"domain": "example.com",
"status": "NOT_STARTED",
"feedback_enabled": true,
"subdomains_enabled": false,
"tracking_enabled": false,
"records": [
{
"type": "TXT",
"name": "agentmail._domainkey",
"value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC..."
},
{
"type": "MX",
"name": "@",
"value": "inbound-smtp.us-east-1.amazonaws.com",
"priority": 10
},
{
"type": "MX",
"name": "mail",
"value": "feedback-smtp.us-east-1.amazonses.com",
"priority": 10
},
{
"type": "TXT",
"name": "mail",
"value": "v=spf1 include:amazonses.com -all"
},
{
"type": "TXT",
"name": "_dmarc",
"value": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
}
],
"created_at": "2026-08-25T09:30:00Z",
"updated_at": "2026-08-25T09:30:00Z"
}Publish the DNS records
Publish every record in the records array at the DNS provider that controls the domain’s authoritative nameservers.
| Record | What it does |
|---|---|
DKIM TXT (host ends in ._domainkey) | Publishes the public key receivers use to check the signature on your mail. |
MX on the domain (@) | Routes inbound mail for the domain to AgentMail so your inboxes receive. |
MX on the mail host | The bounce return path for your outgoing mail. Keep this host to exactly one MX record. |
SPF TXT on the mail host | Authorizes AgentMail’s servers to send for that return path. |
DMARC TXT (_dmarc) | Tells receivers what to do with mail that fails authentication. See Customize DMARC policy. |
Wildcard MX (*) | Present only with subdomains_enabled. Routes mail for every subdomain. |
CNAME (link) | Present only with tracking_enabled. Serves open tracking pixels. |
agentmail domains get-zone-file \
--domain-id "example.com" > example.com.zoneReview the import before applying it. On some providers (Porkbun, for one) a zone file import replaces every existing record, which is fine for a fresh domain but destructive on a domain with other records.
Verify the domain
agentmail domains verify --domain-id "example.com"
agentmail domains get --domain-id "example.com"Instead of polling the get, you can subscribe to the domain.verified webhook event and start creating inboxes when it fires.
The domain’s status tells you where you are:
| Status | Meaning | Next action |
|---|---|---|
NOT_STARTED | Verification has not been requested. | Call verify. |
PENDING | Required records have not been found yet. | Publish the records, then wait for DNS propagation. |
INVALID | At least one record was found but is misconfigured. | Find the record whose status is INVALID and fix its value (for MX records, the priority too). |
FAILED | The records are in place but the verification attempt did not complete. | Call verify again to trigger a recheck. |
VERIFYING | Records are correct and authorization is in progress. | Get the domain again until the status changes. |
VERIFIED | The domain is ready. | Create inboxes on it. |
DNS propagation takes anywhere from a minute to 48 hours depending on the provider.
{
"domain_id": "example.com",
"domain": "example.com",
"status": "PENDING",
"feedback_enabled": true,
"subdomains_enabled": false,
"tracking_enabled": false,
"records": [
{
"type": "TXT",
"name": "agentmail._domainkey",
"value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...",
"status": "VALID"
},
{
"type": "MX",
"name": "@",
"value": "inbound-smtp.us-east-1.amazonaws.com",
"priority": 10,
"status": "VALID"
},
{
"type": "MX",
"name": "mail",
"value": "feedback-smtp.us-east-1.amazonses.com",
"priority": 10,
"status": "VALID"
},
{
"type": "TXT",
"name": "mail",
"value": "v=spf1 include:amazonses.com -all",
"status": "VALID"
},
{
"type": "TXT",
"name": "_dmarc",
"value": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com",
"status": "MISSING"
}
],
"created_at": "2026-08-25T09:30:00Z",
"updated_at": "2026-08-25T09:32:00Z"
}Create the first inbox on the domain
Once the domain is VERIFIED, name it when you create an inbox.
agentmail inboxes create \
--username "support" \
--domain "example.com" \
--display-name "Support"For a pod-owned domain, create the inbox in that pod with the pod inbox route.
{
"organization_id": "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d",
"inbox_id": "support@example.com",
"email": "support@example.com",
"display_name": "Support",
"created_at": "2026-08-25T10:12:04Z",
"updated_at": "2026-08-25T10:12:04Z"
}The new inbox’s address is in the email field, and everything on Send and Receive takes its inbox_id unchanged.
Register a subdomain
Follow the same steps with subdomain.example.com as the domain: every returned host sits under the subdomain, so the root’s mail, in Gmail or Microsoft 365, is untouched. Use this when the root’s mail belongs elsewhere, or when outreach needs a sending reputation it can cycle out.
To host inboxes on any subdomain without registering each one, set subdomains_enabled on a registered domain instead. That adds one wildcard MX record to publish, and then any subdomain works as an inbox’s domain ({ "username": "agent", "domain": "bot.example.com" }). Those inboxes share the parent’s DKIM identity and reputation.
Domain Settings
The update changes a domain’s behavior without touching its registration. Send at least one of feedback_enabled, subdomains_enabled, or tracking_enabled. Omitted fields stay unchanged.
agentmail domains update \
--domain-id "example.com" \
--subdomains-enabled=trueThe response is the updated domain. When the change makes a new DNS record required (enabling subdomains_enabled adds the wildcard MX, enabling tracking_enabled adds the link CNAME), the response includes the refreshed records array so you can publish the new record right away, and a VERIFIED domain returns to PENDING until it verifies. Toggling feedback_enabled takes effect immediately with no DNS change.
When a domain should stop existing, delete it. The delete is permanent. Inboxes on the domain immediately stop sending and receiving, but you keep access to their stored data, so past threads and messages remain readable.
agentmail domains delete --domain-id "example.com"The delete returns a 204 with no body. Deleting frees a slot under your plan’s domain cap, and the name can be registered again afterward.
Scale across multiple domains
Past a single domain, how you spread traffic becomes a deliverability decision:
- Isolate reputations with separately registered subdomains. Agents have different risk profiles, and a high-risk cold outreach agent can drag down the reputation a transactional agent depends on. Register
billing.example.comfor transactional agents,outreach.example.comfor high-volume outreach, andsupport.example.comfor support, each as its own domain. Each registration gets its own DKIM identity, which is what keeps the reputations separate. This is the opposite trade fromsubdomains_enabled, where every subdomain shares the parent’s identity. - Pool domains for high volume. Even a warmed domain has a daily volume ceiling before providers throttle it. Register a pool of root domains (
example.com,example.net,get-example.com), keep the list in your application, and rotate sending inboxes across it. Spreading the volume improves inbox placement at scale, and if one domain’s reputation takes a hit, the rest keep delivering.
New domains also need warming before they can carry volume. See Deliverability for the ramp.
A fleet of domains needs auditing. Listing shows every registered domain in your organization, newest first, which is how you see what exists and drive per-domain checks. All three parameters are optional: limit and page_token page the results (pass the previous response’s next_page_token to resume), and ascending flips to oldest first.
agentmail domains listList entries carry each domain’s settings and timestamps. For a domain’s verification status and a fresh check of its records, get that domain by id.
{
"count": 2,
"domains": [
{
"domain_id": "example.com",
"domain": "example.com",
"feedback_enabled": true,
"subdomains_enabled": true,
"tracking_enabled": false,
"created_at": "2026-08-25T09:30:00Z",
"updated_at": "2026-08-25T10:05:00Z"
},
{
"domain_id": "mail.example.net",
"domain": "mail.example.net",
"feedback_enabled": false,
"subdomains_enabled": false,
"tracking_enabled": false,
"created_at": "2026-08-14T16:20:11Z",
"updated_at": "2026-08-14T17:01:43Z"
}
]
}Verification can lapse after it succeeds. DNS records get edited or deleted by accident, and a VERIFIED domain whose records disappear reverts, which blocks new inbox creation on it. AgentMail rechecks verified domains on its own about once a day, and you can catch drift sooner by getting the domain periodically and alerting when any record’s status leaves VALID.
Customize DMARC policy
AgentMail’s returned DMARC record uses p=reject, the strictest policy: receivers drop mail that fails authentication, which blocks spoofing of your domain. If you want a softer policy, edit the value of the TXT record whose name starts with _dmarc at your DNS provider:
p=quarantinesends failing mail to spam instead of dropping itp=noneonly reports failures without acting on them
Verification keeps passing as long as the record still starts with v=DMARC1 and keeps a rua=mailto: reporting address.