Hi,
I’m getting the following warning in my Stalwart logs:
2026-09-21T06:33:10Z WARN Configuration build warning (registry.build-warning) source = "DnsResolver", id = 20080258862541, key = (null), reason = "The configured DNS resolver cannot validate DNSSEC. DANE has been disabled to avoid deferring mail. Ensure the resolver is DNSSEC-capable and reachable over TCP."
I verified that DNSSEC validation and TCP/53 outbound traffic work perfectly on my host machine.
dig +dnssec +tcp dnssec-failed.org @1.1.1.11.1.1.1
; <<>> DiG 9.20.29-1~deb13u1-Debian <<>> +dnssec +tcp dnssec-failed.org @1.1.1.1
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 16485
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)
;; QUESTION SECTION:
;dnssec-failed.org. IN A
;; Query time: 208 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (TCP)
;; WHEN: Mon Sep 21 19:18:03 CEST 2026
;; MSG SIZE rcvd: 103
What I’ve tried:
In the Web UI and tried configuring a Custom DNS resolver, as well as setting up Quad9, but the result is exactly the same the warning persists in the logs.
Has anyone faced this issue?
Thanks for help.
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.
Stalwart’s DANE support doesn’t just trust the “ad” flag reported by whatever resolver answers your queries. To enable DANE it performs its own internal DNSSEC validation using the hickory resolver library: it builds a second dedicated “DNSSEC resolver” with validate = true and then, at startup, does a DNSKEY lookup for the DNS root (.) and checks that the record comes back cryptographically proven secure through hickory’s own validator (trust anchors baked into hickory, not relying on your upstream server’s AD bit).
That check (ensure_dnssec in crates/common/src/config/smtp/resolver.rs) requires two things to be true, and if either fails you get exactly the warning you’re seeing:
At least one configured name server must use TCP or DNS-over-TLS, not plain UDP. If you picked “Custom” and left the protocol on the default udp, the check fails immediately regardless of DNSSEC support. You need to explicitly set the custom server’s protocol to tcp or tls.
Stalwart itself must be able to reach that server over that protocol and get a validated DNSKEY response for the root zone. For the Quad9 preset, “Use TLS” defaults to true, meaning it dials Quad9 over DNS-over-TLS on port 853. If your container/host can only reach outbound port 53 (UDP/TCP) but not 853, this internal lookup will fail even though dig +tcp on port 53 works fine from your host.
So the fact that your host’s dig +dnssec +tcp ... @1.1.1.1 works over port 53 doesn’t guarantee Stalwart’s own DoT/TCP lookup to Quad9 (port 853) or a Custom resolver configured for UDP will succeed. To fix it:
If using a Custom resolver, make sure each server entry’s protocol is set to tcp or tls (not the default udp).
If using Quad9/Cloudflare with “Use TLS” enabled, confirm the Stalwart host/container can make outbound connections on TCP port 853 (not just 53). Try disabling “Use TLS” to test over plain TCP/53 instead, or check firewall/NAT rules blocking 853.
Check Stalwart’s own logs/network path (not just your shell’s dig), since the validation lookup runs from inside the Stalwart process/container.
@helpbot When setting up custom resolvers over TLS on port 853, the initialization fails even if the port is open. The Web UI lacks a “TLS Hostname” field for custom entries. Switch the custom provider to plain TCP on port 53 when it works.