Check SPF, DMARC, MTA-STS and DNS blocklists per sending domain; count delivery outcomes

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
VeillaxandClaude Sonnet 5.5 committed 2026-10-27 16:56:57 -06:00
1 parent b46e0813fe
commit 3a86254cb6
6 files changed
+864

No files matched your search

+13
View File
@@ -56,6 +56,10 @@ type Config struct {
MailLookupTXT func(name string) ([]string, error) // DNS TXT lookups (DKIM check, MTA-STS record)
MailSTS func(domain string) (*STSPolicy, error) // replaces MTA-STS discovery
MailRootCAs *x509.CertPool // trust anchors for verified TLS to mail servers
MailLookupIP func(name string) ([]net.IP, error) // A/AAAA lookups (SPF a: and exists:)
MailLookupMX func(domain string) ([]string, error) // MX host names (SPF mx:)
MailLookupDNSBL func(name string) ([]string, error) // DNS blocklist queries; no error and no answers means "not listed"
MailBlocklists []string // DNSBL zones to ask; nil uses the built-in list
// GetCertificate replaces Let's Encrypt for https ports (used by tests).
GetCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error)
@@ -100,6 +104,7 @@ type Blacktip struct {
mailChecks map[string]model.MailCheck
mailMu sync.Mutex
mailRate map[string][]time.Time
outcomes outcomeLog
sts stsCache
local map[string]bool
authKey string
@@ -602,8 +607,16 @@ func (b *Blacktip) report() {
rep.UpdateMsg, rep.UpdateID = b.updateMsg, b.updateID
rep.UpdateStage, rep.UpdatePct, rep.UpdateLog = b.updStage, b.updPct, append([]string(nil), b.updLog...)
for id, chk := range b.mailChecks {
chk.Outcomes = b.outcomes.summary(id, time.Now())
rep.MailChecks[id] = chk
}
for id := range b.mail { // an egress that has sent mail but not been checked yet still reports its outcomes
if _, ok := rep.MailChecks[id]; !ok {
if o := b.outcomes.summary(id, time.Now()); o != nil {
rep.MailChecks[id] = model.MailCheck{Outcomes: o}
}
}
}
for id, ms := range b.maps {
st := model.MappingStatus{Error: b.status[id], Cert: b.certStatus(ms.m)}
ms.mu.Lock()