Implements parsing, scoring, CLI output, and UI display for the DMARC
np= tag (DMARCbis draft-ietf-dmarc-dmarcbis), which controls policy for
NXDOMAIN subdomains independently of sp=. The score deducts 15 points
from the base and awards them back when np= is absent (good default) or
its strength is equal to or stricter than the effective sp=/p= policy.
DMARC lookup now follows the full RFC 7489 §6.6.3 fallback chain: exact
From domain → organizational domain (eTLD+1 via PSL) → public suffix
domain (RFC 9091, only when psd=y is present). DNS errors abort
immediately without triggering fallback; NXDOMAIN and missing v=DMARC1
records do trigger it. The found domain is exposed in the new
DMARCRecord.domain field for reporting purposes.
Also promote getOrganizationalDomain to a package-level function so both
HeaderAnalyzer and DNSAnalyzer can share it, and fix pre-existing
rbl_test.go compilation errors and stale score expectations.
Closes: #98
Split api/openapi.yaml schemas into api/schemas.yaml so structs can be
generated independently from the API server code. Models now generate
into internal/model/ via oapi-codegen, with the server referencing them
through import-mapping. Moved PtrTo helper to internal/utils and removed
storage.ReportSummary in favor of model.TestSummary.
CalculateScore now accepts a forWhitelist flag to handle whitelist
scoring logic separately. The final blacklist grade combines both
RBL and DNSWL results using MinGrade for a more accurate reputation
assessment.
Move the ListedCount check before scoringListCount calculation so we
return early with a perfect score when the IP/domain is not listed,
regardless of how many informational-only lists exist.
IPRev and X-Aligned-From now only penalize on failure instead of
contributing positively. Core authentication (SPF/DKIM/DMARC) rebalanced
to 30 points each, BIMI stays at 10, totaling 100 base points.
Bug: https://github.com/happyDomain/happydeliver/issues/11
Ensures parseLegacySPF only trusts Received-SPF headers where the
receiver= field matches the configured receiverHostname, preventing
incorrect SPF results from unrelated receivers.
Embed rspamd-symbols.json in the binary to provide human-readable
descriptions for rspamd symbols in reports. Optionally fetch fresh
symbols from a configurable rspamd API URL (--rspamd-api-url flag),
falling back to the embedded list on error. Update the frontend to
display descriptions alongside symbol names and scores.
Add params field to SpamTestDetail, update RspamdResult.symbols to
reference SpamTestDetail instead of the now-removed RspamdSymbol schema,
and update Go code accordingly.
Remove authResults parameter from AnalyzeDNS, making it independent of
the authentication analysis step. Instead, parse DKIM-Signature headers
directly to extract domain and selector.
Bug: https://github.com/happyDomain/happydeliver/issues/11
Add DefaultInformationalRBLs (UCEPROTECT L2/L3) and track listings
separately via RelevantListedCount so these broader lists are displayed
but excluded from the deliverability score calculation.
Detect the List-Unsubscribe-Post: List-Unsubscribe=One-Click header
(RFC 8058) and expose it as the 'one-click' unsubscribe method in the
content analysis. When unsubscribe methods are present but one-click is
absent, the summary card now shows a warning nudging senders to adopt it.