panel: show the SPF and DMARC records the domain page expects

The domain page generated and displayed the DKIM record but said only
"also configure SPF and DMARC for the domain (see the documentation)".
The concrete example existed — buried in the check's remediation text,
and only visible once the check had already failed. Show both records up
front, host and value with a Copy button, the way the DKIM record is
shown, plus the two things that actually bite: a domain may carry only
one SPF record (add the mechanism to the existing one rather than
publishing a second), and p=none is safe to publish immediately.

The SPF value names the addresses SELFPOST_HOSTNAME resolves to, taken
from the hostname check the page already runs, and falls back to an "a:"
mechanism when it does not resolve. New dnscheck.SPFExample/DMARCExample
are the single source for both the page and the checks' advice, so the
two cannot drift into recommending different records; dnscheck.Query
gains Hostname for the fallback.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 16:08:48 +03:00
parent 6cf8b7b631
commit e6910c2c2d
8 changed files with 199 additions and 15 deletions
+2 -2
View File
@@ -61,7 +61,7 @@ func (c *Checker) checkDKIM(ctx context.Context, q Query) Result {
// checkDMARC reports whether the domain publishes a DMARC policy. DMARC is not
// required for delivery, so its absence is advice (warn), not a fault.
func (c *Checker) checkDMARC(ctx context.Context, domainName string) Result {
name := "_dmarc." + domainName
name := DMARCRecordName(domainName)
txt, found, err := c.lookupTXT(ctx, name)
if err != nil {
return lookupFailed("the DMARC record", err)
@@ -76,7 +76,7 @@ func (c *Checker) checkDMARC(ctx context.Context, domainName string) Result {
if !found || len(records) == 0 {
return Result{
Status: health.StatusWarn,
Detail: fmt.Sprintf("No DMARC record at %s. Delivery works without one, but publishing at least \"v=DMARC1; p=none; rua=mailto:you@%s\" tells receivers what to do with mail that fails DKIM and gets you reports.", name, domainName),
Detail: fmt.Sprintf("No DMARC record at %s. Delivery works without one, but publishing at least %q tells receivers what to do with mail that fails DKIM and gets you reports.", name, DMARCExample(domainName)),
}
}
if len(records) > 1 {