On this page
Module 3: DNS and Domain Configuration
Learning Objectives
By the end of this module, you will be able to:
- Explain the purpose of MX, A, AAAA, CNAME, TXT, and PTR records in the context of mail flow.
- Explain DNS hierarchy, authoritative resolution, propagation, caching, and TTL well enough to correctly set customer expectations after a DNS change.
- Distinguish split (internal vs. external) DNS resolution and recognize when it explains a customer-reported symptom.
- Read raw SPF, DKIM, and DMARC DNS records and identify correct vs. incorrect syntax.
- Perform and interpret MX, TXT, and PTR lookups using standard tools, and know which data is safe to check via public tools vs. which requires the customer's own zone access.
- Apply a structured decision tree to a DNS-adjacent mail-flow symptom.
- Explain the security implications of common DNS misconfigurations (missing/incorrect SPF, unpublished DMARC, absent rDNS).
Key Terminology
- MX record
- Declares which host(s) accept mail for a domain, with a priority value (lower number = more preferred).
- A / AAAA record
- Maps a hostname to an IPv4 / IPv6 address. MX records point to hostnames, which must in turn resolve via A/AAAA.
- CNAME record
- An alias pointing one hostname to another. Cannot coexist with other record types at the same name — a common misconfiguration source.
- TXT record
- Free-form text at a DNS name; used for SPF, DKIM (at a selector subdomain), DMARC, and domain-verification tokens.
- PTR record (reverse DNS / rDNS)
- Maps an IP address back to a hostname; looked up via the special
in-addr.arpa(IPv4) orip6.arpa(IPv6) zones. - TTL (Time To Live)
- How long a resolver is permitted to cache a DNS answer before re-querying, in seconds.
- Authoritative name server
- The name server that holds the actual, source-of-truth zone data for a domain, as opposed to a caching resolver.
- Split DNS (split-horizon)
- A configuration where internal and external queries for the same name return different answers (e.g., an internal mail hostname resolving differently inside the corporate network than from the public internet).
- Selector (DKIM)
- The subdomain label (e.g.,
selector1._domainkey.example.com) under which a specific DKIM public key is published, allowing multiple keys to exist for one domain.
Lesson
In Module 1 you learned that email is a chain of discrete systems, and in Module 2 you saw how that chain is physically arranged for a given deployment. This module supplies the addressing layer underneath both of those pictures: the Domain Name System (DNS) records that tell the rest of the internet where a domain's mail should go, and — just as important for a security product — which senders a domain has actually authorized to speak for it. DNS problems are disproportionately common in support tickets for a simple reason: DNS is edited by hand (or by whichever administrator last touched a zone file), it is invisible until something breaks, and its effects are frequently delayed, cached, and inconsistent depending on who is looking and when. By the end of this module you should be able to read a domain's DNS records the way you read an SMTP transcript in Module 1 — literally, methodically, and without guessing.
3.1 DNS Records Relevant to Mail — What Each One Actually Does
Six record types account for almost every DNS-adjacent mail-flow ticket you will see. Learn to read each one on sight, because a huge share of DNS troubleshooting is simply knowing which record to check first — and the record that deserves checking first, nearly every time, is the one covered next.
MX (Mail Exchanger). An MX record is published at the domain's apex (or a subdomain) as a priority/hostname pair:
example.com. 3600 IN MX 10 mx1.example-secure.com.
example.com. 3600 IN MX 20 mx2.example-secure.com.
The lower priority number wins: sending MTAs try the lowest-numbered host first and fall back to higher-numbered hosts only on failure. A domain with no MX record but an A record still technically accepts mail, per RFC 5321's implicit-MX fallback behavior — but treat that as legacy behavior, not a supported design. If you find it in a customer's zone, it usually indicates an oversight worth flagging, not a working alternate configuration someone chose deliberately.
A / AAAA. The hostname an MX record points to must itself resolve to an IP address via an A (IPv4) or AAAA (IPv6) record. This dependency is easy to overlook, and that is exactly why it is worth leading with as the first thing you check on any DNS-adjacent ticket: a correct MX record pointing to a hostname with no A/AAAA record produces a complete, silent mail-flow failure. Sending systems cannot connect at all — there is no NDR to read, no partial delivery, nothing in the customer's own logs to hint at the cause, because from the sender's perspective there is simply nowhere to connect to. It is one of the highest-value quick checks in DNS troubleshooting precisely because it is fast to verify (one lookup) and catastrophic when broken.
Worked Example: The MX Record That Points Nowhere
Here's what that failure looks like in practice, and why it is worth internalizing as your default first move on any "mail isn't arriving at all" ticket. Start with the MX lookup:
$ dig MX example.com +short
10 mx1.example-secure.com.
20 mx2.example-secure.com.
That looks completely healthy — two MX hosts, sensible priorities, nothing obviously wrong. The mistake a new engineer makes here is stopping at this point and moving on to look for the problem somewhere else. The record only tells you a hostname was declared; it says nothing about whether that hostname actually resolves. So the very next lookup, every time, is the A record for the MX target itself:
$ dig A mx1.example-secure.com +short
(no answer returned — NXDOMAIN)
$ dig A mx2.example-secure.com +short
(no answer returned — NXDOMAIN)
Neither MX target resolves to anything. Every sending MTA on the internet that tries to deliver to this domain gets exactly this same result: an MX record that names a host, and no way to open a connection to that host. There's no bounce for the customer to forward you, because most sending systems will queue and retry silently for a while before generating an NDR — which means the customer's first symptom is often simply "nothing is arriving," with no error text anywhere. This is precisely why 3.1 and the lookup sequence in 3.10 are meant to be used together: MX and A are a matched pair, and checking one without the other tells you almost nothing.
CNAME. Never place an MX record's target behind a CNAME. This isn't a stylistic preference — per RFC 2181/974 guidance, some sending MTAs will simply refuse to follow a CNAME when resolving an MX target, which means delivery reliability becomes implementation-dependent on the sending side, an unpredictable failure mode you cannot fully control from the receiving domain's configuration. There's a second, unrelated trap with CNAMEs worth knowing cold: a CNAME record cannot coexist with any other record type — including MX or TXT — at the exact same name. Attempting to add a TXT record (for SPF, say) at a name that already has a CNAME is a common, hard-to-diagnose misconfiguration, because the failure is silent — the new TXT record simply doesn't take effect as expected, or the zone becomes invalid, and nothing about the DNS provider's UI necessarily warns the customer at the moment they make the change.
TXT. TXT records carry SPF (at the domain apex or the subdomain being evaluated), DMARC (always at _dmarc.<domain>), DKIM public keys (at <selector>._domainkey.<domain>), and domain-ownership verification tokens for the security product itself and various other services. Because TXT records are unstructured free text, multiple unrelated TXT records commonly coexist at the same DNS name with no conflict — that's normal. The trouble comes from two very specific, very common mistakes: a customer or another vendor overwriting an existing SPF TXT record entirely instead of adding to it (destroying whatever authorization was already published), or — equally common, and covered in full in 3.5 — publishing two separate SPF records at the same name, which is not a graceful "more specific one wins" situation but an outright validation failure.
PTR (reverse DNS). A PTR record maps a sending IP address back to a hostname. Many receiving systems check for PTR existence, and further check for forward-confirmed reverse DNS (FCrDNS — meaning the PTR's hostname, when looked up again via A/AAAA, resolves back to the original IP), as a baseline reputation signal for outbound mail. A customer's outbound deliverability complaint with no PTR record at all, or a PTR that exists but doesn't forward-confirm, is a very common — and very easily verified — root cause. Keep this in your back pocket; it comes back directly in 3.8 and in the knowledge check.
3.2 DNS Hierarchy and Authoritative Resolution
DNS resolution walks a hierarchy: root servers, then top-level-domain (TLD) servers (e.g., the servers responsible for all of .com), then the domain's own authoritative name servers — the specific servers declared by that domain's NS records, typically hosted at the registrar or a DNS provider. Only those authoritative servers hold the actual source-of-truth zone data. Every other server in the chain — public resolvers, ISP resolvers, corporate forwarders, browser and OS-level caches — is relaying or caching an answer it fetched from that authority at some point in the past.
This matters practically, not just academically: when diagnosing a DNS record, query the domain's own authoritative name servers directly (dig @<authoritative-ns> ...) whenever there is any doubt at all. A public resolver's cached answer can be stale, or — in rare cases — poisoned, and it is not proof of what the zone actually contains right now. Treat "what does a public lookup tool show" and "what does the domain's own authority say" as two different questions, and reach for the second whenever the stakes of getting it wrong are non-trivial.
Worked Example: When the Public Resolver and the Authoritative Server Briefly Disagree
Here's a case that makes 3.2's warning concrete instead of abstract. Suppose a customer's DNS provider lowers a record's TTL and then changes the record itself, as part of a planned cutover. Query a public resolver a few minutes later and you might see this:
$ dig MX example.com +short # via a public resolver
10 old-mx.example.com.
$ dig MX example.com @ns1.example-dns.com +short # via the domain's own authoritative NS
10 mx1.security-vendor.com.
Two different, both-momentarily-true answers for the same question. The public resolver is not wrong or broken — it is correctly returning an answer it cached before the change, and hasn't yet re-queried because its cached TTL hasn't expired. The authoritative server is returning the current, live state of the zone. If you only ever check the public resolver, you might wrongly conclude the customer's change never took effect, when in fact it did — you were just looking at a cached echo of the old world. This is the practical reason 3.2 tells you to go to the authority directly whenever a finding matters: it removes the caching layer as a variable entirely.
3.3 Propagation, Caching, and TTL
"DNS propagation" is a term customers use as though it describes some mysterious network-wide broadcast delay. It doesn't. It is really just cache expiration, distributed across every resolver on the internet that happened to have cached the old answer — and it is governed by the TTL the old record was published with, not the new one. A customer who changes an MX record that previously carried a TTL of 86,400 seconds (24 hours) should be told, accurately, that some resolvers worldwide may continue returning the old answer for up to that long. That is normal, expected behavior — not a fault in the new record, and not a fault of the receiving system that appears to be "still using the old settings."
This is worth treating as a customer-communication skill as much as a technical one. When a customer asks about propagation, what they are almost always really asking is some version of "am I in trouble right now" — and a vague, generic answer only increases their anxiety and the chance they escalate. A precise, confident, TTL-based answer does the opposite: it turns an open-ended worry into a bounded, explainable window. Best practice, worth recommending to customers proactively rather than only after something goes wrong, is to lower the TTL to something short — 300 seconds is a common choice — before a planned cutover, then raise it again once the change is confirmed stable. A short TTL before a change means a short, predictable propagation window if anything needs to be rolled back or adjusted.
The practical troubleshooting implication: if a customer reports a DNS-dependent symptom immediately after changing a record, your very first question should be "what was the previous TTL, and how long ago did you make the change relative to it?" That single question often fully explains the symptom without any further investigation being necessary at all.
3.4 Split DNS
Some organizations run split-horizon DNS, where internal clients resolve a name — often the mail hostname itself — to an internal IP address, while external, public resolution of that exact same name returns a different, internet-routable IP. This is a legitimate and fairly common design choice, not a misconfiguration by itself. But it has a direct consequence for how you troubleshoot: an engineer resolving a hostname from their own machine may see a completely different answer than what the customer's mail servers, or the internet at large, actually see.
Always ask the customer directly, or verify with a public/multi-location lookup tool, whether split DNS is in play before treating a locally-observed DNS answer as ground truth for an internet-facing mail-flow problem. This is a frequent enough trap that it earns its own branch later in the decision tree in 3.11: any time a symptom seems to differ depending on who's looking, split DNS should be one of the first things you rule in or out.
3.5 SPF — Record Syntax and Common Errors
A valid SPF record is a single TXT record starting with v=spf1:
example.com. 3600 IN TXT "v=spf1 ip4:203.0.113.0/24 include:_spf.security-vendor.com ~all"
SPF has a short list of high-frequency misconfigurations, and one of them is, by a wide margin, the single most-missed fact among new engineers — it's worth slowing down for.
Beyond duplicate records, three other patterns account for most of the rest of SPF troubleshooting:
-
Exceeding the 10 DNS-mechanism-lookup limit. Each
include,a,mx,ptr,exists, andredirectmechanism counts toward this limit, and exceeding it is also a PermError. This is very common when a domain accumulatesincludemechanisms for many vendors over time — a marketing platform, a CRM, a security product, a ticketing system — without ever pruning old entries that are no longer actually in use. -
Using
+all(explicit pass-all). This effectively disables SPF's usefulness entirely, since it authorizes literally any sending IP. It's almost always an accident rather than an intentional choice — often left over from early testing — and it's worth flagging to a customer even when it isn't the immediate subject of the ticket you're working. -
Missing the security product's own required
include:. This is a common day-one onboarding gap. If the product sends or relays mail on the customer's behalf — outbound scanning, or bounce/quarantine notifications sent as the customer's own domain — its SPF include is typically required for that mail to pass SPF cleanly.
Worked Example: Two SPF Records, One PermError
Here's what the duplicate-SPF failure actually looks like when you run into it, so the abstract rule above has a concrete shape attached to it. Pull all TXT records at the domain apex:
$ dig TXT example.com +short
"v=spf1 ip4:203.0.113.0/24 -all"
"v=spf1 include:_spf.google.com ~all"
"google-site-verification=abc123..."
Two of these three lines both begin with v=spf1. That alone is enough to know the domain's SPF is broken before you even look closely at either record's content — it doesn't matter that the first one looks stricter (-all, hard fail) or that the second one includes a legitimate-looking Google mechanism. Run this through any SPF-checking tool and you'll get a PermError result, not a "partial pass" or "the stricter one applies." The fix is always the same shape: the customer needs to consolidate every authorized sender into a single SPF TXT record — typically by merging the mechanisms from both existing records into one line — not add a third record or try to make the two coexist.
3.6 DKIM — Selectors and Records
A DKIM public key is published as a TXT record at <selector>._domainkey.<domain>:
selector1._domainkey.example.com. 3600 IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBA...=="
Because the selector portion of the name is chosen independently by whichever system is signing the mail, there is no single "the DKIM record" for a domain the way there is a single MX record set. A domain can — and commonly does — have several DKIM selectors active simultaneously, one per signing system: the mailbox platform itself, marketing or transactional-email tools, and potentially the security product, if it signs outbound mail.
The common errors here are worth being able to recognize immediately: a truncated public key, where the p= value is cut off partway through — often the result of a copy-paste error, or a DNS provider mishandling a long TXT record's string-splitting; a selector name typo, where what the signing system expects to publish under does not match what was actually published in DNS; and a stale key, left behind in DNS after the signing side rotated to a new key but the old DNS record was never removed or updated. Any of these produces the same downstream symptom — signature verification failing for every message using that selector — even though the underlying causes are quite different, which is exactly why you need to actually look at the record rather than assume.
3.7 DMARC — Record Syntax
A DMARC record is always published at _dmarc.<domain> — never at the apex itself, and never without the leading underscore:
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc-agg@example.com; ruf=mailto:dmarc-forensic@example.com; adkim=s; aspf=r"
Six fields carry almost all of the record's meaning, and you should be able to read each one at a glance: p= is the policy (none, quarantine, or reject) applied to mail that fails DMARC evaluation; pct= is the percentage of failing mail the policy actually applies to — and this one deserves particular attention, because a record with p=reject but pct= set to something less than 100 will, by design, still let some failing mail through untouched. That's a frequent point of customer confusion: they read "reject" and assume every failing message is blocked, when the record itself says otherwise. rua= names the destination for aggregate reports; ruf= names the destination for forensic/failure reports, which are increasingly unsupported by major receivers for privacy reasons — do not assume a customer will actually receive ruf= reports simply because they published the field. And adkim=/aspf= set the alignment mode — s for strict or r for relaxed — a concept covered in full depth in Module 4, but worth being able to recognize by sight here.
3.8 Reverse DNS, Domain Verification, and Reputation
Beyond the PTR mechanics covered in 3.1, sending reputation is also shaped by factors like domain age, leftover verification records from onboarding other services, and the general hygiene of a domain's subdomains. One pattern worth actively watching for: parked or unused subdomains that have no MX record and no explicit SPF/DMARC policy of their own. These are a known abuse vector — an attacker can spoof mail that appears to come from a legitimate organization's unused subdomain, and because that subdomain has published no policy telling receivers what to do with unauthorized mail claiming to be from it, there's nothing in place to reject the spoof.
The recommendation worth giving customers proactively, not just reactively after an incident: publish a restrictive DMARC and SPF policy on parked or non-sending domains and subdomains too, not only on the ones actively sending mail. For a domain that legitimately never sends mail, that typically looks like:
parked.example.com. 3600 IN TXT "v=spf1 -all"
_dmarc.parked.example.com. 3600 IN TXT "v=DMARC1; p=reject;"
An SPF record of v=spf1 -all hard-fails every sender, since none are authorized, and a DMARC policy of p=reject tells receivers to reject anything claiming to be from that name that fails evaluation. Together, they close off a subdomain that would otherwise sit silently available for impersonation.
3.9 Correct vs. Incorrect Examples — Reference Set
Use this table as a quick-reference sanity check when you're staring at a raw record and need to confirm whether what you're looking at is actually valid.
| Record type | Correct | Incorrect | Why |
|---|---|---|---|
| SPF |
v=spf1 include:_spf.example.com -all as a single TXT record |
Two separate TXT records both starting v=spf1
|
RFC 7208 PermError — multiple SPF records for one name is explicitly invalid, not "most specific wins" |
| SPF |
v=spf1 include:vendorA.com include:vendorB.com -all (6 total lookups) |
An accumulation exceeding 10 total DNS mechanism lookups | PermError on lookup-limit overflow |
| MX |
10 mx1.example.com. (trailing dot, resolves via an A record) |
10 mx1.example.com pointed at a CNAME |
MX targets must resolve directly via A/AAAA, not through a CNAME, per RFC guidance |
| DMARC | Published once at _dmarc.example.com
|
Published at dmarc.example.com (missing underscore) |
Wrong name — evaluators find no DMARC record at all, and silently default to no policy |
| DKIM | v=DKIM1; k=rsa; p=<full unbroken key> |
p= value truncated mid-string |
Signature verification fails for every message using that selector |
| PTR | IP resolves to a hostname, and that hostname's A record resolves back to the same IP (FCrDNS) | PTR exists but does not forward-confirm, or is entirely absent | Reduces sender reputation; some receivers reject outright on missing PTR |
3.10 Lookup and Validation Procedures
Whatever the exact shape of a DNS-adjacent ticket, the same standard sequence of lookups applies. Run these in order — each one either confirms the previous layer is healthy or tells you exactly where to stop and start digging:
-
dig MX <domain>(ornslookup -type=MX <domain>) — confirm the current MX records and their priority. -
dig A <mx-hostname>— confirm the MX target actually resolves. Never skip this step; a healthy-looking MX record with an unresolvable target is exactly the silent failure worked through in 3.1. -
dig TXT <domain>— retrieve every TXT record at the apex, then manually isolate the one (there should be exactly one) beginningv=spf1. -
dig TXT _dmarc.<domain>— retrieve the DMARC record. -
dig TXT <selector>._domainkey.<domain>— retrieve a specific DKIM record. The selector must be known in advance, or extracted from an actual signed message'sDKIM-Signature:header, which names its own selector via thes=tag — you cannot guess it. -
dig -x <IP>— a reverse lookup for the PTR record. - Whenever any doubt about staleness exists, repeat the relevant lookup against the domain's own authoritative name servers explicitly (
dig @<ns> ...), per 3.2.
Worked Example: A Full DNS Health Check, Start to Finish
Here's what running the complete sequence looks like end to end against a real (sanitized) domain, narrated as you'd talk yourself through it on a live ticket:
$ dig MX example.com +short
10 mx1.example-secure.com.
20 mx2.example-secure.com.
→ MX looks healthy. Two hosts, sane priorities.
$ dig A mx1.example-secure.com +short
198.51.100.20
→ Resolves. Good — the MX target isn't a dead end.
$ dig TXT example.com +short
"v=spf1 ip4:203.0.113.0/24 include:_spf.security-vendor.com ~all"
→ Exactly one v=spf1 record. No duplicate. Syntax looks well-formed.
$ dig TXT _dmarc.example.com +short
"v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc-agg@example.com"
→ Present, correctly named, policy is quarantine at 100%.
$ dig TXT selector1._domainkey.example.com +short
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBA...=="
→ Present, key doesn't look truncated (ends cleanly, no obvious cutoff).
$ dig -x 203.0.113.10 +short
mail-out.example.com.
$ dig A mail-out.example.com +short
203.0.113.10
→ PTR exists and forward-confirms (FCrDNS). Reputation baseline is intact.
Six lookups, about a minute of work, and you've either confirmed the entire DNS surface is healthy or found exactly where it isn't — without a single guess along the way. This is the sequence worth running by habit on every DNS-adjacent ticket, even when the customer's description points you toward one specific record; a problem they haven't noticed yet in an adjacent record is common enough that the full sweep pays for itself.
3.11 Troubleshooting Decision Tree — DNS-Adjacent Symptom
When a mail-flow ticket looks like it might be DNS-related, work through the questions below in order. The order is deliberate: it starts with the fastest, highest-value check (does the MX chain even resolve?) and only moves on to slower or more nuanced questions once that's been ruled out.
A couple of things worth noticing about why the tree is shaped this way. First, checking MX/A resolution comes before anything else because it's both the fastest check and, when broken, the most complete explanation — there's no reason to investigate SPF syntax on a domain whose mail can't even connect. Second, the "was anything changed recently" question comes second, before diving into content-level record analysis, because a huge share of DNS tickets are really propagation-timing questions in disguise, and it's far faster to rule that out than to carefully analyze a record that turns out to be perfectly correct and just not fully propagated yet. Only once both of those are cleared does the tree move on to authentication-specific and split-DNS-specific branches — the more nuanced, slower-to-verify possibilities.
dig/lookup output — not a paraphrase of what it showed. DNS findings are exactly the kind of evidence that should never be represented from memory or summary; the next person working the ticket needs to see the same record you saw, not your recollection of it.Hands-On Lab
Lab 3.1 — Full DNS Health Check
You'll be given five lab domains, each seeded with one or more misconfigurations — a missing A record for an MX target, a duplicate SPF record, a truncated DKIM key, a misnamed DMARC record, or a missing PTR record (sometimes more than one issue per domain). For each domain:
- Run the full lookup sequence from 3.10 (MX → A → TXT/SPF → TXT/DMARC → TXT/DKIM selector → PTR).
- Identify every misconfiguration present — don't stop at the first one you find; some domains have more than one.
- Write a one-paragraph, plain-language, customer-facing explanation for each finding, using the plain-language standard covered in Module 18 (Customer Communication).
Deliverable: a completed findings worksheet covering all five domains, including your raw lookup output and your customer-facing explanation for each finding, reviewed against the answer key.
Scenario-Based Exercise
Scenario: A customer changed their MX records 45 minutes ago to point at the security product as part of an onboarding cutover. They're now reporting that "some mail is still bypassing the new filter." They don't know their previous TTL.
Task: Draft the exact diagnostic sequence you would run — which lookups, in what order, against which name servers — to determine whether this is propagation lag or an actual misconfiguration. Then draft the customer-facing status update you would send, assuming your finding turns out to be propagation lag with an unknown-but-likely-short remaining window. Tie your reasoning explicitly back to 3.2, 3.3, and the decision tree in 3.11.
Knowledge Check
Answer each question yourself before expanding it.
1. A domain has two separate TXT records that both start with v=spf1. What is the result under RFC 7208, and why?
2. Why can't an MX record's target hostname be a CNAME?
3. A customer changed their DMARC record 10 minutes ago and it's not yet reflected in a public lookup tool. Is this necessarily broken? What determines the answer?
4. What does FCrDNS mean, and why does it matter for outbound deliverability?
5. Why must a DKIM selector be known before you can look up the correct DKIM TXT record, and where do you find it?
DKIM-Signature: header via the s= tag — you cannot guess it. It must be read from an actual signed message (or from documentation) before the corresponding <selector>._domainkey.<domain> TXT record can be looked up.6. A customer's internal staff can reach mail.example.com but say external partners report connection failures to the same name. What DNS concept should you investigate first?
7. What is the maximum number of DNS mechanism lookups SPF permits, and what happens when a record exceeds it?
include, a, mx, ptr, exists, and redirect. Exceeding it produces a PermError, causing SPF evaluation to fail for the domain regardless of the record's intended content.Common Misconceptions
Key Takeaways
- Check MX and its A/AAAA target together, every time, before anything else — it's the fastest check and, when broken, the most complete explanation for total silent mail-flow failure.
- Never quote a generic propagation window. Check the *previous* TTL and the elapsed time since the change, and give the customer a precise, confident answer built from those two numbers — it defuses escalation pressure far better than a vague one does.
- Two SPF records at the same name is a hard PermError, not a "most specific wins" situation. This is the single most-missed fact in this module — make sure it's actually solid before you move on.
- When a symptom differs depending on who's observing it, suspect split DNS before you suspect anything more exotic, and verify with a public, multi-location lookup rather than trusting your own machine's resolution.
- When you propose a DNS-related root cause, back it with the actual
dig/lookup output in your ticket notes — never a paraphrase. It's the kind of evidence that should never be represented from memory, and it's an easy habit to build early.