{"record":{"id":"85e8c749e8e12ae3","repo":"Billionmail/BillionMail","slug":"no-spf-record-found","errorCode":null,"errorMessage":"No SPF record found","messagePattern":"No SPF record found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/relay/relay_v1_list_relay_configs.go","lineNumber":212,"sourceCode":"\t}\n\n\tvar spf string\n\tvar finalErr error\n\ttxts, err := net.LookupTXT(domain)\n\tif err != nil {\n\t\tg.Log().Debug(ctx, \"DNS TXT query failed:\", domain, \"Error:\", err)\n\t\tfinalErr = err\n\t} else {\n\t\tfound := false\n\t\tfor _, txt := range txts {\n\t\t\tif strings.HasPrefix(txt, \"v=spf1\") {\n\t\t\t\tspf = txt\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tfinalErr = fmt.Errorf(\"No SPF record found\")\n\t\t}\n\t}\n\n\tif spf != \"\" {\n\n\t\tspfCache.Set(ctx, cacheKey, spf, 5*time.Minute)\n\t\treturn spf, nil\n\t} else {\n\t\t//  Unable to find or query failed. Cache the \"not_found\" flag with a validity period of 2 minute.\n\t\tspfCache.Set(ctx, cacheKey, \"not_found\", 2*time.Minute)\n\t\treturn \"\", finalErr\n\t}\n}\n","sourceCodeStart":194,"sourceCodeEnd":226,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/relay/relay_v1_list_relay_configs.go#L194-L226","documentation":"This is the direct (non-cached) failure: net.LookupTXT succeeded but none of the returned TXT records started with 'v=spf1', so the domain has no SPF record. The function then caches 'not_found' for 2 minutes, so subsequent attempts for that TTL return the '(from cache)' variants.","triggerScenarios":"GetRealSPFRecord called (via ListRelayConfigs) for a domain whose TXT records exist but contain no 'v=spf1' record, or whose TXT lookup returns no relevant entries.","commonSituations":"Freshly created sending domain where SPF was never published; SPF configured on the wrong name; DNS provider not yet propagating the record.","solutions":["Publish an SPF TXT record at the domain root, e.g. 'v=spf1 include:_spf.example.com ~all'","Verify propagation with 'dig TXT domain' or an online SPF checker","Confirm you are checking the exact domain used as the envelope sender","Retry after 2 minutes to bypass the negative cache"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// pre-check the domain before calling the API\nconst hasSpf = await dns.resolveTxt(domain)\n  .then(records => records.some(r => r.startsWith('v=spf1')))\n  .catch(() => false);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Publish an SPF TXT record at the domain apex","Verify with dig TXT after DNS changes","Allow propagation time before testing relays","Check the exact domain, not a subdomain"],"tags":["dns","spf","txt-record","email"],"backgroundTag":"spf-record-missing","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}