Issue Description
Outbound delivery to DANE/TLSA-enabled domains fails permanently with
“Bogus DNSSEC record … details = TLSA”, even though the exact same TLSA
and the full DNSSEC chain validate cleanly with dig/delv on the same host
(via both a public resolver and the internal resolver Stalwart uses).
The verdict is a false-positive: the records ARE DNSSEC-signed and DO validate.
Stalwart’s built-in DNSSEC validator flags them as Bogus regardless of which
resolver backend is configured. Because a Bogus verdict is a hard-fail even in
DANE “optional” mode (strict = false in the logs), this silently blocks mail to
every DANE-enabled destination.
Expected Behavior
Stalwart should validate the (correctly signed, externally-validatable) TLSA
records successfully and deliver over the DANE-authenticated TLS channel.
Actual Behavior
Every delivery attempt fails with a “Bogus DNSSEC record” for the TLSA lookup
and the message is rescheduled, eventually temp-failing with:
“DANE authentication failure: Bogus TLSA records were found”.
Relevant Log Output
- Send an email to any recipient whose MX host publishes correctly
DNSSEC-signed TLSA records (i.e. a domain where DANE is in effect and the
TLSA + DNSSEC chain validate cleanly with external tooling). - Observe repeated “Bogus DNSSEC record … details = TLSA” in the logs and
the message never leaving the queue (eventually temp-failing with
“DANE authentication failure: Bogus TLSA records were found”). - On the SAME host, validate the identical records independently
(dig +dnssec / delv) — they return the AD flag and validate successfully,
confirming the “Bogus” verdict is a false positive.
The issue is not specific to any single provider — it should occur for any
destination publishing valid, DNSSEC-signed TLSA records.
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
This appears related to the June 2026 reports that “Stalwart’s resolver does
its own DNSSEC validation that no resolver choice disables” (which flagged a
legitimate NODATA AAAA as bogus), and to open issue #2328 “DANE TLSA support
looks far from correct”. This report is the signed-TLSA variant of the same
class of false-positive.
NOTE: All addresses, domains, IPs, and IDs below have been anonymized.
- [email protected] = a local sender address on my own domain
- example.org = my own mail domain
- recipient.tld = the destination domain (publishes signed TLSA)
- mx1.recipient-mx.tld / mx2.recipient-mx.tld = the destination MX hosts
- 10.0.0.53 = my internal recursive resolver
- = queue identifiers
— Independent Validation (same host, proves records are NOT bogus) —
Public resolver — note the ‘ad’ (Authenticated Data) flag is SET:
$ dig +dnssec TLSA _25._tcp.mx2.recipient-mx.tld @9.9.9.9
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
_25._tcp.mx2.recipient-mx.tld. 1200 IN TLSA 3 1 1
_25._tcp.mx2.recipient-mx.tld. 1200 IN TLSA 3 1 1
_25._tcp.mx2.recipient-mx.tld. 1200 IN RRSIG TLSA 8 5 1200 recipient-mx.tld. …
Full-chain validation:
$ delv TLSA _25._tcp.mx2.recipient-mx.tld +rtrace
;; fetch: _25._tcp.mx2.recipient-mx.tld/TLSA
;; fetch: recipient-mx.tld/DNSKEY
;; fetch: recipient-mx.tld/DS
;; fetch: tld/DNSKEY
;; fetch: tld/DS
;; fetch: ./DNSKEY
; fully validated
Same query against the internal resolver Stalwart uses — ‘ad’ flag also SET:
$ dig +dnssec TLSA _25._tcp.mx2.recipient-mx.tld @10.0.0.53
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
The destination signing-zone DNSKEY is ~1708 bytes → forces TCP fallback
(works fine with dig):
$ dig +dnssec DNSKEY recipient-mx.tld @10.0.0.53
;; Truncated, retrying in TCP mode.
;; flags: qr rd ra ad; … (returns full DNSKEY set, validated over TCP)
Host clock is correct and NTP-synchronized; RRSIG inception/expiration windows
are current (well within validity). So this is neither clock skew nor expired
signatures nor a broken zone at the destination.
— Relevant Log Output (full lines, anonymized, times in UTC) —
2026-07-16T08:42:46Z INFO Queued message submission for delivery (queue.authenticated-message-queued) queueId = , from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, nextRetry = 2026-07-16T08:42:46Z, nextDsn = 2026-07-17T08:42:46Z, expires = 2026-07-19T08:42:46Z
2026-07-16T08:42:46Z INFO Delivery attempt started (delivery.attempt-start) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2
2026-07-16T08:42:46Z INFO New delivery attempt for domain (delivery.domain-delivery-start) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”
2026-07-16T08:42:46Z INFO Fetched TLS-RPT record (tls-rpt.record-fetch) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, details = [“https://reports.recipient.tld/reports/smtptls”], elapsed = 119ms
2026-07-16T08:42:46Z INFO Fetched MTA-STS policy (mta-sts.policy-fetch) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, strict = true, details = [“mx1.recipient-mx.tld”, “mx2.recipient-mx.tld”], elapsed = 42ms
2026-07-16T08:42:47Z INFO Host authorized by MTA-STS policy (mta-sts.authorized) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, hostname = “mx1.recipient-mx.tld”, details = [“mx1.recipient-mx.tld”, “mx2.recipient-mx.tld”], strict = true
2026-07-16T08:42:47Z INFO Bogus DNSSEC record (dane.bogus-dnssec-record) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, hostname = “mx1.recipient-mx.tld”, details = “TLSA”, strict = false, elapsed = 43ms
2026-07-16T08:42:47Z INFO Host authorized by MTA-STS policy (mta-sts.authorized) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, hostname = “mx2.recipient-mx.tld”, details = [“mx1.recipient-mx.tld”, “mx2.recipient-mx.tld”], strict = true
2026-07-16T08:42:47Z INFO Bogus DNSSEC record (dane.bogus-dnssec-record) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, domain = “recipient.tld”, hostname = “mx2.recipient-mx.tld”, details = “TLSA”, strict = false, elapsed = 39ms
2026-07-16T08:42:47Z INFO Message rescheduled for delivery (queue.rescheduled) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, nextRetry = 2026-07-16T08:44:47Z, nextDsn = 2026-07-17T08:42:46Z, expires = 2026-07-19T08:42:46Z
2026-07-16T08:42:47Z INFO Delivery attempt ended (delivery.attempt-end) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 10116, total = 2, elapsed = 344ms
The identical “Bogus DNSSEC record” verdict repeats on every subsequent retry
(08:44, 08:49, 08:59, 09:14, 09:44, 10:44, 12:44), always ~40ms elapsed,
for both mx1.recipient-mx.tld and mx2.recipient-mx.tld. Eventually:
2026-07-16T15:33:41Z INFO DSN temporary failure notification (delivery.dsn-temp-fail) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 7460, total = 2, to = “[email protected]”, hostname = “mx2.recipient-mx.tld”, details = “DANE authentication failure: Bogus TLSA records were found”, nextRetry = 2026-07-16T19:35:44Z, expires = 2026-07-18T15:33:41Z, total = 8
2026-07-16T15:33:41Z INFO DSN temporary failure notification (delivery.dsn-temp-fail) queueId = , queueName = “remote”, from = “[email protected]”, to = [“[email protected]”, “[email protected]”], size = 7460, total = 2, to = “[email protected]”, hostname = “mx2.recipient-mx.tld”, details = “DANE authentication failure: Bogus TLSA records were found”, nextRetry = 2026-07-16T19:35:44Z, expires = 2026-07-18T15:33:41Z, total = 8
Note the fast fail (~40 ms) on the Bogus verdict, which suggests a
validation/logic issue rather than a network timeout while fetching the
oversized (1708-byte, TCP-only) DNSKEY of the destination’s signing zone.
Note also that MTA-STS authorizes the same hosts (strict = true) in the same
attempt, so name resolution and connectivity to the MX hosts are fine.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on