Good DNS record troubleshooting for email begins with an uncomfortable fact: when SPF, DKIM or a tracking CNAME will not verify, the cause is rarely the record you meant to publish. It is usually how your DNS panel stored it. A key that was longer than 255 characters, a domain name that was added twice, a pair of quotes that became part of the value, a second SPF record, or an old answer that has not yet expired from a cache. We will go through each of these, show how to check them with dig and nslookup, and finish with a table you can use by symptom.
How email records live in DNS
Every email authentication method rests on a handful of record types. SPF and DKIM are published as TXT records, DMARC is a TXT record at a name starting with _dmarc, and many sending platforms ask for CNAME records for a return-path or tracking hostname. MX records route inbound mail. A resolver asks for a name and a type, and the answer carries a time to live, or TTL, which tells every cache how long it may reuse it.
Three details explain most of the trouble. First, DNS panels are friendly front ends over a zone, and each one makes its own choices about names, quotes and splitting. Second, caches exist at several layers, so the same name can give different answers in different places for a while. Third, some record types exclude each other at the same name. We cover the full set of records in our authentication guide and the verification flow in verifying your sending domain. This article is the diagnostic companion.
Check the right place first: authoritative nameservers
Before changing anything, find out what is actually published. A public resolver such as the one your laptop uses may hold an older answer. The authoritative nameservers are the servers that hold your zone and give the definitive answer, so we always ask them first.
# 1. Find the authoritative nameservers for the domain
dig NS example.com +short
# 2. Ask one of them directly for the record (no cache involved)
dig TXT selector1._domainkey.example.com @ns1.dns-host.example +noall +answer
# 3. Compare with what a public resolver says
dig TXT selector1._domainkey.example.com @9.9.9.9 +noall +answer
# 4. Check the TTL and the negative caching value
dig SOA example.com @ns1.dns-host.example +noall +answer
# nslookup equivalent
nslookup -type=TXT selector1._domainkey.example.com ns1.dns-host.example
If the authoritative answer is wrong, the problem is in the panel: fix the record. If the authoritative answer is right and the public resolver is different, the problem is a cache: wait. If both are right and verification still fails, you are probably checking the wrong name, or the platform expects a different record type. This single comparison removes more guesswork than anything else in this article.
Tip: Check from a machine that does not use your own DNS cache, and remember that a result from a web-based checker reflects that checker resolver, not yours.
TXT strings over 255 characters and DKIM 2048-bit keys
A TXT record carries one or more character-strings, and each character-string is limited to 255 bytes. This comes from the original DNS format in RFC 1035, which stores each string with a one-byte length. A record may hold several strings, and for SPF and DKIM the receiver joins them in order without adding spaces. The specifications for both say so (RFC 7208 for SPF, RFC 6376 for DKIM).
The practical impact is on DKIM. A 1024-bit RSA public key in base64 sits close to the limit once you add the version and key type tags, while a 2048-bit key is roughly twice as long, so the p= value alone is several hundred characters. It must be stored as more than one string. Our guide to DKIM key rotation, selectors and key length explains why 2048-bit keys are worth the effort.
| How your panel behaves | What you should do | How to verify |
|---|---|---|
| Splits long values automatically | Paste the full value once, with no quotes and no line breaks | dig shows several quoted strings that together read as the full key |
| Expects you to enter quoted chunks | Split at any point under 255 characters, wrap each part in quotes, separate with a single space | The joined text equals the original key exactly |
| Rejects values over 255 characters | Look for a setting for long records or a different record editor; ask the host if none exists | Lookup returns the complete key, not a truncated one |
| Silently truncates the value | Re-enter in chunks and read the result back | A key that ends early fails DKIM with a key or syntax error |
What a correct split looks like
The example below shows the shape of a split record. The key text is invented and shortened for illustration. In a real record the chunks add up to the full key supplied by your platform.
selector1._domainkey.example.com. 3600 IN TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"
"q1x2example0invented0key0chunk0one0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
"IDAQAB" )
Two traps are common. Do not add a space inside the key when you split it, because the receiver concatenates the strings and a space would become part of the key. And do not cut the record in the middle of the selector or tag names. If a split key fails, compare the joined result against the original, character by character, using a text diff rather than your eyes.
Registrar and DNS panel quirks
The same record can be entered four different ways in four panels. These are the quirks we see most often.
The domain is appended twice
Many panels add the zone name automatically. If you type selector1._domainkey.example.com in the host field, the panel may store selector1._domainkey.example.com.example.com. The symptom is that the record exists in the panel but a lookup of the right name returns nothing. Enter only the relative part, selector1._domainkey, and use @ or leave the field empty for the apex, depending on the panel. A trailing dot normally marks a name as fully qualified in zone files, but web panels differ, so read the saved name back with dig.
Quotes, line breaks and invisible characters
Copying a value from a web page or document can bring along smart quotes, non-breaking spaces or a line break. If the panel also adds its own quotes, you may end up with a literal quote character at the start of the value, and a record that begins with a quote does not start with v=spf1 or v=DKIM1, so it is not recognised. Paste into a plain text editor first, then into the panel, and read the result back.
The wrong record type or the wrong name
Platforms sometimes ask for a TXT record where you might expect a CNAME, or the other way around. Use the type exactly as instructed. Also check that you are on the right zone: if the domain uses nameservers at one provider but you edited the zone at your registrar, the edit is never served. The NS lookup shown earlier tells you where the live zone is.
| Symptom in the panel | Likely cause | Fix |
|---|---|---|
| Record shows the domain twice in the name | Panel appended the zone to a full name | Enter the relative name only |
| Value starts and ends with quote characters in lookup output only once | Normal for TXT output from dig | No change needed |
| Value contains escaped quotes or a quote at the start | You added quotes and the panel added its own | Remove your quotes |
| Record saved but lookup returns nothing | Edited a zone that the live nameservers do not serve | Edit the zone at the provider named by the NS records |
| Panel will not accept an underscore in the name | Name validation rule in the panel | Use another editor mode or ask the DNS provider |
CNAME at the apex, flattening and record conflicts
A CNAME says that a name is an alias for another name, so the resolver should follow it and use the answers there. For that reason a CNAME cannot coexist with any other record at the same name (RFC 1034 and RFC 2181). The root of your domain, the apex, must carry SOA and NS records, and usually has MX and TXT as well, so a CNAME at the apex is not valid.
Some DNS providers work around this with flattening or an alias record type. The provider looks up the target itself and returns ordinary address records at the apex. This helps for pointing your root web address at a hosted service. It does not help for email authentication. If a platform asks for a CNAME on a hostname such as a subdomain, put it on that subdomain. If a platform asks for a CNAME on the bare domain, ask them for an alternative such as TXT and address records.
The conflict also works the other way round. If you add a CNAME for a name that already has a TXT record, for example a DKIM selector that you previously published as TXT, one of them will be rejected or ignored, depending on the panel. Delete the old record before adding the CNAME. This situation is common during a provider change, and our migration guide covers the order of steps.
Duplicate SPF records and other duplicates
A domain may publish only one SPF record, which is a TXT record starting with v=spf1. If receivers find two, the result is a permanent error (RFC 7208), and SPF fails for every message, not just the ones from one vendor. This happens when two teams each add the record their vendor asked for.
| Situation | What receivers see | Fix |
|---|---|---|
| Two TXT records both beginning v=spf1 | Permanent error, SPF does not pass | Merge into one record with all include mechanisms |
| One record, more than 10 lookups | Permanent error after the lookup limit | Flatten or remove includes; see the SPF lookup guide |
| Two DMARC records at _dmarc | The policy may be ignored | Keep one record |
| Same selector published twice with different keys | Unpredictable key selection | Delete the old key or use a new selector |
Merging is simple in principle: take the include and ip4 mechanisms from each record, put them in one v=spf1 record, and end with a single all qualifier. The harder part is the lookup count, which we explain in the SPF permerror guide and managing several vendors on one domain.
Proxied records: turn the DNS proxy off for mail
Some DNS providers offer a proxy mode, often shown as a coloured cloud icon beside a record. In this mode the provider answers queries for the name with its own addresses and passes web traffic through its network. That is useful for websites and unhelpful for mail.
If a mail-related CNAME is proxied, the lookup no longer returns the target your sending platform expects. Verification fails, tracking or return-path hostnames do not resolve to the right server, and HTTPS certificates for tracking domains may not issue. A mail server hostname that is proxied will not accept SMTP connections at all, because the proxy handles web ports rather than mail. So set every record related to email to the DNS only mode: MX targets, mail server A records, the CNAMEs for return-path and tracking hostnames, and DKIM CNAMEs. TXT records are never proxied, so they are not affected. Our guide to return-path and tracking domains explains why those hostnames must resolve directly to the platform.
Check: A dig query for a proxied name returns addresses that do not belong to your platform even though you saved a CNAME. That is the sign that the proxy is on.
TTL choices and change planning
TTL is the number of seconds a resolver may keep an answer. A long TTL reduces queries and makes the record more resilient if your nameservers are briefly unavailable. A short TTL lets you recover quickly from a mistake. The sensible approach is to vary it by phase.
| Phase | Suggested TTL | Why |
|---|---|---|
| Building or testing a new record | 300 to 600 seconds | Corrections show up quickly |
| Before a planned change | Lower the TTL well ahead of the change, at least as long as the current TTL | Old caches expire before you switch |
| The day of the change | Keep it short | You can roll back |
| Stable records | 3600 seconds up to a day | Fewer queries and less exposure to outages |
The key point of change planning is that lowering a TTL does not help instantly. Caches that already hold the record keep it for the old TTL. If a record has a TTL of 86400 seconds, lower it at least a day before the change. Then change the value, wait, verify and raise the TTL again.
Propagation and negative caching
DNS changes do not spread out from a single point. There is no global push. What people call propagation is simply the time it takes for caches to expire. The authoritative servers answer with the new value as soon as the zone is saved and loaded, and each resolver switches when its cached copy ends. Some resolvers ignore very low TTLs or keep answers a little longer, so allow a margin.
There is a second cache that is easy to forget: the negative cache. If a resolver asked for a name that did not exist yet, it remembers the not-found answer, and RFC 2308 says the time is based on the SOA record (the smaller of the SOA TTL and its minimum field). If your platform checked the record a few minutes before you added it, the failure can stay cached until that time runs out, even though the record now exists.
A worked example
Imagine a domain whose DKIM TXT record was published at 10:00 with a TTL of 3600 seconds and a SOA negative caching time of 900 seconds. At 10:05 the platform checks too early and gets not-found, so that resolver caches the failure until about 10:20. At 10:10 you notice a typo, correct the key and save it. The authoritative servers now give the new answer. A resolver that cached the first record at 10:00 may still serve the old one until 11:00. One that cached not-found may serve it until 10:20. So a fully clean result from every resolver could take until 11:00, but a check that goes straight to the authoritative servers passes at 10:10. In this case you use the authoritative result to confirm that your edit is correct, then wait for the longest cache time, 60 minutes, before pressing the verify button again.
When the platform retries checks automatically, you may not need to do anything. When it only checks on a button press, wait for the longest cache period you calculated. Do not change the record again while you wait, because each change restarts the clock for caches that refresh.
A diagnostic table by symptom
| Symptom | Most likely cause | First check | Fix |
|---|---|---|---|
| Platform says the DKIM record is not found | Name doubled, wrong zone, or not yet propagated | dig the exact selector name at the authoritative server | Correct the host field or wait for caches |
| DKIM verifies but the signature fails with a key error | Key truncated or split with a space | Join the TXT strings and compare with the original | Re-enter in chunks without spaces |
| SPF returns permerror | Two SPF records or over 10 lookups | dig TXT at the apex and count v=spf1 records | Merge records, reduce lookups |
| SPF record seems ignored | Literal quote or leading space in the value | Look for a value that does not start with v=spf1 | Remove stray characters |
| CNAME refuses to save | Another record exists at that name, or the name is the apex | List all record types at the name | Remove the conflict or use a subdomain |
| CNAME exists but verification fails | DNS proxy on, or target mistyped | Does dig return the expected target? | Set to DNS only, correct target |
| Works on your computer, fails on the platform | Different resolver caches | Query the authoritative server and two public resolvers | Wait for the older TTL |
| Record exists but check still reports not found | Negative caching | Look at the SOA values and the time of the first check | Wait the negative cache time |
| DMARC report shows no policy | Record at the wrong name | Check that the name begins with _dmarc | Move it to _dmarc.yourdomain |
Header-level problems, as opposed to record-level problems, are easier to confirm in the message itself. See how to read email headers for what the authentication results mean once DNS is right.
A practical routine you can repeat
- Identify. Write down the exact name and type that your platform asks for.
- Locate. Find the live nameservers with an NS lookup and confirm you are editing that zone.
- Enter. Use the relative host name, paste the value without added quotes, and split long strings only if your panel needs it.
- Read back. Query the authoritative server and compare the result with the original.
- Clean up. Remove duplicates, old selectors with the same name, and conflicting record types.
- Proxy off. Confirm mail-related records are set to DNS only.
- Wait smartly. Compute the longest of the old TTL and the negative caching time.
- Verify. Run the platform check and send a test message. Check your MigoSMTP account or API documentation for the exact record names and values to publish.
Checklist before you ask for help
- The record name was read back from the authoritative nameserver and matches exactly what the platform asked for.
- No domain suffix appears twice in the stored name.
- The value has no pasted quotes, no line breaks and no spaces inside long keys.
- Long TXT values are present in full when strings are joined.
- Only one SPF record exists at the name, and the lookup count is within the limit.
- No CNAME shares a name with another record, and no CNAME sits at the apex.
- Every mail-related record is set to DNS only, not proxied.
- You have waited for the old TTL and the negative caching time before rechecking.
- The zone you edited is the one that the NS records point to.
Stuck on a record that will not verify? Send us the record name, the exact value you published, and the output of a dig query against your authoritative nameserver, and we will help you find the difference.
Further reading and sources
Frequently asked questions
Why does my DKIM record say it is too long?
A single DNS character-string can hold at most 255 bytes, and a 2048-bit RSA public key in base64 is longer than that. The record itself can hold several strings, and receivers join them without spaces. Some panels split the value for you, some ask you to enter quoted chunks, and some reject a long value outright. Check how your panel handles it and verify the result with a TXT lookup.
Should I put quotes around my TXT value?
It depends on the panel. Many web forms add the quotes for you, so adding your own produces a literal quote character in the value and the record fails to parse. Zone file editors and some command line tools expect quotes. Read the record back with dig after saving, and if you see doubled or escaped quotes, remove yours.
Why did my record end up as selector._domainkey.example.com.example.com?
The panel appends your domain to whatever you type in the host field. If you enter the full name, the domain is added twice. Enter only the part before your domain, such as selector._domainkey, or follow the hint shown in the panel. A trailing dot usually tells a panel that the name is complete, but not every panel treats it that way, so test with a lookup.
Can I put a CNAME on my root domain?
Standard DNS does not allow it, because a CNAME cannot share a name with other records and the root domain must carry SOA and NS records. Some providers offer a flattening or alias feature that returns address records at the root. Use that for web traffic if you need it, but do not use it as a substitute for the TXT and MX records that email needs at the root.
I have two SPF records. Is that really a problem?
Yes. A domain must publish only one SPF record, and receivers that find more than one return a permanent error rather than choosing one. Merge the mechanisms into a single record. Our guide to multiple vendors on one domain explains how to do that without exceeding the lookup limit.
How long should I set the TTL?
Use a short TTL such as 300 to 3600 seconds while you are building or changing records, and a longer one such as several hours to a day once things are stable. The right number is a trade-off between how fast you can roll back and how much load you place on your nameservers.
I fixed the record but the check still fails. Why?
Either a resolver is still holding the old answer until its TTL runs out, or it is holding a cached not-found answer until the negative caching time ends, or you are checking a different name than the one the platform looks up. Query the authoritative nameservers to see the truth, then wait for caches.
Why must mail CNAMEs not be proxied?
A DNS proxy answers queries with its own addresses instead of the real target of your record. A mail platform needs to see the CNAME target or the real server address, so a proxied record fails verification and can break tracking or bounce handling. Set those records to DNS only.
Which tool should I trust: dig, nslookup or a web checker?
All of them are fine if you know what they ask. dig and nslookup let you choose the server, which is the key to separating a publishing problem from a caching problem. Web checkers usually query from one location through a public resolver, so a mismatch with your local result often just means different caches.