Zone migrations break mail in a predictable way. Whoever moved the domain copied the records they could see on the website — A, CNAME, maybe MX — and did not copy the ones that only matter to mail servers. SPF, DKIM keys, DMARC, and any subdomain records for a bounce domain quietly vanish, and inbound or outbound mail starts failing anywhere from immediately to a day later as caches expire.
Step 1 — Which nameservers is the world actually using?
Before checking any record, confirm which zone is authoritative. If the registrar delegation still points at the old provider, you are editing a zone nobody is reading.
# Delegation as published by the parent zone
dig +short NS example.com
# Ask the registrar's view directly (TLD servers), bypassing caches
dig +trace NS example.com | tail -8
# Zone serial from each authoritative server — mismatches mean an incomplete transfer
dig +short SOA example.comTwo things go wrong here. The delegation was changed at the registrar but the old provider is still serving a copy of the zone, so some resolvers get stale answers; or the delegation was never changed and the new zone is inert. The NS record lookup and SOA lookup show both sides. If different resolvers disagree, the DNS compare tool puts Google, Cloudflare, Quad9, and OpenDNS side by side, and the propagation checker fans the same query out worldwide.
Step 2 — Is inbound mail routed at all?
MX is the record that decides whether anyone can send *to* you. It is also the record most likely to have been retyped by hand and got wrong.
dig +short MX example.com
# 1 smtp.google.com.
# Confirm each MX target actually resolves to an address
dig +short A smtp.google.com
# The same query against a specific resolver, to spot cache disagreement
dig @1.1.1.1 +short MX example.com
dig @8.8.8.8 +short MX example.com- Empty result — the MX records were not migrated. Mail is being delivered to the A record if one exists, or bouncing outright.
- MX pointing at a hostname that does not resolve — a target with no A/AAAA record is a dead MX. Every target must resolve.
- MX pointing at a CNAME — not permitted; MX targets must be hostnames with address records. Some receivers tolerate it, many do not.
- Priorities inverted — mail still flows but through the wrong server first. See MX priority explained.
- Old provider's MX left in place alongside the new one — mail splits between two systems and users report "some mail arrives, some does not".
Step 3 — Did SPF, DKIM, and DMARC survive the move?
This is where the actual answer usually is. All three live in TXT records, and TXT records are the ones migration tools and hand-copying miss most reliably. Check all three in one pass:
# SPF — must return exactly one v=spf1 string
dig +short TXT example.com | grep spf1
dig +short TXT example.com | grep -c spf1
# DMARC
dig +short TXT _dmarc.example.com
# DKIM — replace with the selector from a real message's DKIM-Signature s= tag
dig +short TXT google._domainkey.example.com
dig +short CNAME selector1._domainkey.example.com
# Everything published at the apex, in one view
dig +short TXT example.com| Symptom | Likely cause | Where to look |
|---|---|---|
| Outbound mail lands in spam everywhere | SPF record missing entirely | SPF checker |
dmarc=fail on messages that used to pass | DKIM key not migrated, or published at the wrong name | DKIM checker |
| Rejections citing the domain's DMARC policy | DMARC survived at p=reject but SPF/DKIM did not | DMARC checker |
| SPF permerror | Two v=spf1 records — old and new both present | SPF PermError guide |
| A single ESP's mail fails, everything else is fine | Bounce-domain subdomain records not carried over | TXT lookup |
Two subtleties worth knowing. First, DKIM at Microsoft 365 is published as CNAMEs, not TXT records, and migration tools that only look for TXT will drop them — query with dig CNAME as well. Second, a DMARC record that survived while SPF and DKIM did not is the worst combination: the policy is still enforcing but nothing can satisfy it, so mail that previously delivered is now actively rejected. If you find that, either restore the authentication records immediately or temporarily set p=none while you do.
mail.example.com or bounces.example.com, that subdomain has its own SPF record, its own DKIM records, and sometimes its own MX for bounce handling. None of it is visible when you look at the apex.Step 4 — Is PTR still correct?
If you moved hosting at the same time as DNS, your outbound IP changed, and reverse DNS is set by whoever owns the new IP block — not in your zone. Microsoft and Yahoo both treat missing or generic reverse DNS as a strong negative signal.
# What is my sending IP resolving back to?
dig +short -x 203.0.113.25
# mail.example.com.
# And does that name resolve forward to the same address?
dig +short A mail.example.comBoth directions must agree, and the hostname should look like a mail server rather than a dynamic-pool name. Check it with the reverse DNS lookup; set a PTR record on your VPS covers where the setting lives at common providers.
Step 5 — Is it caching rather than configuration?
Once the records are demonstrably correct, the remaining question is who has not seen them yet. Resolvers hold the previous answer for the TTL it carried, not the TTL of the new record, so a record that used to have a 24-hour TTL can keep serving the old value for most of a day after you fix it.
# Remaining TTL as a cache sees it — count it down by re-running
dig MX example.com +noall +answer
# Bypass caches entirely and ask an authoritative server
dig @ns1.example-dns.net MX example.com +norecurse
# Compare two public resolvers
dig @1.1.1.1 +short TXT example.com
dig @8.8.8.8 +short TXT example.comIf the authoritative server returns the right answer and public resolvers do not, you are waiting on TTLs and there is nothing to fix. If the authoritative server itself returns the wrong answer, the record is wrong. That single test settles most "is it propagation?" arguments — the propagation checker and DNS compare make it visual, and how long does DNS propagation take explains what actually controls the timing.
Step 6 — Can mail servers actually reach you?
If DNS is provably correct and mail still bounces, move down the stack. Confirm the MX host accepts connections on port 25 and that your submission ports are open for outbound clients.
# Does the MX host answer, and does STARTTLS work?
openssl s_client -starttls smtp -connect mail.example.com:25 -crlf < /dev/null 2>&1 \
| grep -E "CONNECTED|subject=|Verify return code"
# Submission port for authenticated clients
openssl s_client -starttls smtp -connect mail.example.com:587 -crlf < /dev/null 2>&1 | head -5The SMTP connection test and port checker do the same from outside your network, which matters because a firewall rule that follows a server move is invisible from the server itself. Port 465 vs 587 vs 25 covers which port should be open for which job.
Step 7 — Reputation, last
A new IP has no sending history, and a recycled one may carry someone else's. If authentication is clean and connectivity is fine but delivery is still poor, run the blacklist check on the new IP and ramp volume gradually rather than sending a full campaign on the first day.
The deliverability test runs SPF, DKIM, DMARC, MX, and PTR together and is the fastest way to re-confirm the whole picture once you have made changes. Follow it with a real test message and read the Authentication-Results header in the header analyzer — that header is the only thing that tells you what a receiver actually concluded.
How to avoid this next time
- Export the old zone before you migrate, as a zone file if the provider offers one, and diff it against the new zone afterwards. Not "look at the dashboard" — an actual diff.
- Lower TTLs 24–48 hours ahead so a mistake is reversible in minutes. See lower your TTL before a DNS migration.
- Enumerate TXT and CNAME records explicitly. They carry SPF, DKIM, DMARC, and domain verification, and they are the ones that get missed.
- Keep the old zone live at the previous provider until you have confirmed the new one is answering correctly everywhere.
- List your sending subdomains before the move, not after. Bounce domains and DKIM selectors do not appear in an apex-level review.
- Verify from outside, not from a machine whose resolver you already flushed.