DNS setup
The four DNS records for mxgate, how mxgate setup writes them at Cloudflare, Vercel or Porkbun, how to add them by hand, and how to read the check.
A domain needs two DNS records to receive mail through mxgate, and one more to send. This page shows the records, the command that writes them, and how to read the check result.
The records
| Record | Value | Required | Purpose |
|---|---|---|---|
TXT _mxgate.example.com | mxgate-verify=<token> | Yes | It proves that you control the domain. mxgate accepts no mail for the domain before this record exists. |
MX example.com | mx1.mxgate.io, priority 10 | Yes | It sends the mail of the domain to mxgate. Remove other MX records on the same name. |
TXT mxgate._domainkey.example.com | v=DKIM1; k=rsa; p=<key> | Only for send-as | The DKIM key of the domain. Forwarding works without it. |
TXT _dmarc.example.com | v=DMARC1; p=none | No | Add it only if the domain has no DMARC record. Keep a record that exists. |
Each domain has its own token and its own DKIM key. mxgate domain add, mxgate domain show and GET /v1/domains/{domain} give the exact values in records. For the use of the DKIM key, see Send as your domain.
One command: mxgate setup
CLOUDFLARE_API_TOKEN=... npx mxgate setup example.com --to you@gmail.commxgate setup writes the records at these DNS hosts:
| DNS host | Environment variables | What it needs |
|---|---|---|
| Cloudflare | CLOUDFLARE_API_TOKEN | A token with the permission Zone, DNS, Edit on the zone. |
| Vercel | VERCEL_TOKEN, VERCEL_TEAM_ID | Set VERCEL_TEAM_ID only when the domain is in a team. |
| Porkbun | PORKBUN_API_KEY, PORKBUN_SECRET_API_KEY | Turn on API access for the domain in Porkbun. |
The token stays on your machine. The CLI calls the DNS host from there, and mxgate does not get the token.
The command does these steps:
- It adds the domain to your account and gets the records.
- It reads the NS records of the domain to find the DNS host.
--dns cloudflare|vercel|porkbunskips this step. - It reads the zone and makes a plan. It prints the plan:
+for a record to add,-for a record to remove,=for a record that is correct already,!for a conflict. - It adds the new records first and removes records after that, so the domain always has an MX record.
- It runs the mxgate check each 10 seconds until ownership and MX are correct, for at most 120 seconds.
--wait <seconds>changes the limit. - With
--to, it sets the catch-all*@example.comto those mailboxes.
An existing mail server
If the domain has MX records that point to another server, the result is a conflict. The command stops and changes nothing at the DNS host. With --replace-mx, the command deletes those MX records, and all mail for the domain moves to mxgate.
Dry run
--dry-run prints the plan and changes nothing at the DNS host. The domain is still added to your mxgate account.
Another DNS host
If mxgate does not know the DNS host, or the token is not set, the command prints the records and stops. Add them by hand.
By hand
$ npx mxgate domain add example.com
example.com pending aliases: 0
DNS records:
required TXT _mxgate.example.com mxgate-verify=...
required MX example.com 10 mx1.mxgate.io
optional TXT _dmarc.example.com v=DMARC1; p=none
optional TXT mxgate._domainkey.example.com v=DKIM1; k=rsa; p=...
Publish the required records, then run: mxgate domain verify example.comPublish the records at your DNS host. Then run the check:
npx mxgate domain verify example.comThe API calls are POST /v1/domains with {"name":"example.com"} and POST /v1/domains/example.com/verify.
The check result
The check looks up the records now and stores the result in checks.
| Field | Value | Meaning |
|---|---|---|
ownership | ok | The TXT record has the correct value. The domain is verified. |
ownership | fail | The TXT record is not there, or it has a different value. |
mx | ok | Each MX record points to mxgate. |
mx | warn | MX points to mxgate and also to other servers. Some mail does not go to mxgate. Remove the other MX records. |
mx | fail | There is no MX record, or MX points only to other servers. |
dkim | ok | The DKIM record has the key of the domain. Send-as can be used. |
dkim | fail | There is no DKIM record, or it has a different key. Only send-as needs it. |
mx_found | A list | The MX records that the check found, for example 10 mx1.mxgate.io. |
problems | A list | One sentence for each problem, with the exact record to correct. |
verified is true when ownership is proven. Mail arrives when the MX record also points to mxgate. mxgate domain verify has exit code 0 when the domain is verified, and 1 when it is not.
DNS changes can take some minutes. If the check does not see a new record, wait and run it again.
One account can run 20 checks one after the other. After that, one more check becomes available each 30 seconds. Above the limit the answer is 429 rate_limited with retry_after_seconds.
Check any domain
$ npx mxgate check example.com
example.com
ok mx mail goes to mxgate
10 mx1.mxgate.io
warn spf no SPF record: mail sent as this domain is easy to spoof and often lands in spam
ok dmarc DMARC policy none
v=DMARC1; p=none
receiver: mxgate; can receive mail: yesmxgate check reads the MX, SPF and DMARC records of any domain from your machine. It needs no account and sends nothing. It says who receives the mail of the domain: mxgate, another provider, or nobody. The exit code is 0 when the domain can receive mail. The MCP tool is check_dns.
Quickstart
From no account to forwarded mail in about two minutes: sign up, run one setup command, check the log. Then the same flow as four API calls.
Forwarding and aliases
How mxgate aliases and the catch-all work, why a destination must confirm, and what happens to a message between the sender and your mailbox.