Docs pages

Hosts#

A key manages a list of hosts. A host is a whole domain (example.com) or a name inside one (advisor.example.com). You manage records at each host and under it (_dmarc.advisor.example.com, google._domainkey.advisor.example.com).

When a key's host is a name inside a domain, everything else in that root domain belongs to someone else: you never see it and can't change it. The rest of this page is about that case; for a whole-domain host, the host and the root are the same name.

Two ways to address a host#

Every API style accepts either form, call by call.

1. The host as its own domain (simplest)#

Put the host in domain (Dynadot style) or in the path (Spaceship style):

  • Records at the host are main records (Dynadot) or name @ (Spaceship).
  • Records under it use the part in front of the host as the subhost or name: _dmarc, google._domainkey.
Shell
curl https://api.maildns.io/api3.json \
  --data-urlencode key=KEY --data-urlencode command=set_dns2 \
  --data-urlencode domain=advisor.example.com \
  --data-urlencode add_dns_to_current_setting=1 \
  --data-urlencode subdomain0=_dmarc \
  --data-urlencode sub_record_type0=txt \
  --data-urlencode 'sub_record0=v=DMARC1; p=quarantine'

2. Root domain plus subhost#

Put the root domain in domain and the full name under it as the subhost, the way registrars normally store subdomain records. Scripts written against a registrar often work this way already.

Shell
curl https://api.maildns.io/api3.json \
  --data-urlencode key=KEY --data-urlencode command=set_dns2 \
  --data-urlencode domain=example.com \
  --data-urlencode add_dns_to_current_setting=1 \
  --data-urlencode subdomain0=_dmarc.advisor \
  --data-urlencode sub_record_type0=txt \
  --data-urlencode 'sub_record0=v=DMARC1; p=quarantine'

In root form, get_dns lists only your hosts' records, all as subhosts. Main records (Dynadot) and @ (the other styles) mean the root domain itself, which is not yours: sending one is an error.

Both forms in each style#

Style Host form Root form
Dynadot domain=advisor.example.com; main records, or subdomain0=_dmarc domain=example.com; subdomain0=_dmarc.advisor
Spaceship /dns/records/advisor.example.com; names @, _dmarc /dns/records/example.com; names advisor, _dmarc.advisor
Cloudflare the host's zone (/zones?name=advisor.example.com); names @, _dmarc or full the root's zone (/zones?name=example.com); full names
GoDaddy /v1/domains/advisor.example.com/records; names @, _dmarc /v1/domains/example.com/records; names advisor, _dmarc.advisor
Porkbun /dns/create/advisor.example.com; name empty or _dmarc /dns/create/example.com; name advisor or _dmarc.advisor
Namecheap SLD=advisor.example&TLD=com; HostName1=@ or _dmarc SLD=example&TLD=com; HostName1=advisor or _dmarc.advisor

Replies name records the way each style does: Cloudflare and Porkbun give full names, the others give names relative to what you addressed.

The same records in both forms#

Full name Type Host form: domain=advisor.example.com Root form: domain=example.com
advisor.example.com TXT, MX main record, or name @ subhost advisor
google._domainkey.advisor.example.com TXT google._domainkey google._domainkey.advisor
_dmarc.advisor.example.com TXT _dmarc _dmarc.advisor
mail.advisor.example.com CNAME mail mail.advisor
example.com any not reachable not yours: error
www.example.com any not reachable not yours: error

Which form to use#

  • One host at a time: host form. Names are shorter and there is only one way to get them right.
  • Several hosts in the same root domain in one call: root form. One call (set_dns2, PUT, PATCH, setHosts) can carry records for every host your key has in that root, and it is applied as one change.
  • Reading: either. In root form, reads return the records of all your hosts in that root, and nothing else.

Replace calls work per host#

Some calls replace instead of adding: every host the call mentions ends up with exactly the records in the call, including the records under it. Hosts the call does not mention keep all their records.

Style Replaces Adds
Dynadot set_dns2 without add_dns_to_current_setting=1 set_dns2 with add_dns_to_current_setting=1
GoDaddy PUT /records; PUT /records/{type} (that type only) PATCH /records
Namecheap setHosts, always none: read with getHosts and send everything back
Spaceship never PUT
Cloudflare never (PUT replaces one record by id) POST
Porkbun never (editByNameType changes one type at one name) /dns/create
  • In host form, the call mentions the host in domain.
  • In root form, it mentions each host that one of its subhosts belongs to: _dmarc.advisor mentions advisor.example.com.

Careful: a replace that sends only the DMARC record (subdomain0=_dmarc.advisor, or HostName1=_dmarc) leaves advisor.example.com with that one record. Its MX, SPF, verification and DKIM records are removed. Use the add call unless you mean to replace.

On Dynadot, GoDaddy and Namecheap themselves a replace rewrites the whole domain. MailDNS limits it to the hosts you name, so a record forgotten for one host can't take another host down.

Listing hosts#

Every style lists your key's hosts and nothing else: list_domain (Dynadot), GET /api/v1/domains (Spaceship), GET /zones (Cloudflare), GET /v1/domains (GoDaddy), /domain/listAll (Porkbun), namecheap.domains.getList (Namecheap). Hosts can't be added through the API.

Names that are not yours#

You sent Reply (Error or detail)
A domain that is neither one of your hosts nor the root of one could not find domain in your account (404 in the styles that use status codes)
A name in the root that is not at or under one of your hosts www.example.com is not one of your hosts (403)
A main record with domain set to the root main records of example.com are not on your account; set records on your hosts with subdomain0 / sub_record_type0 / sub_record0 (403)