Issue Description
Stalwart correctly resolves the sender domain’s DMARC record and reports its policy as reject, but when both SPF and DKIM fail, the resulting DMARC status is dmarc.none (“No DMARC record”) instead of dmarc.fail.
The spam filter consequently assigns DMARC_NA (1.00) instead of DMARC_POLICY_REJECT (4.00).
Expected Behavior
When a valid p=reject DMARC record exists and neither SPF nor DKIM provides an aligned pass, the DMARC result should be dmarc.fail.
The spam filter should assign DMARC_POLICY_REJECT, not DMARC_NA.
Actual Behavior
Stalwart finds the DMARC policy and reports policy = "reject", but returns:
result = No DMARC record (dmarc.none)
The spam classifier assigns DMARC_NA (1.00). The reproduced message received a total score of 10.90 and was accepted into the Spam mailbox.
Reproduction Steps
- Use a sender domain with a valid DMARC record containing
p=reject. The issue was reproduced with bothexample.comand another independently managed domain. - From an unauthenticated external SMTP connection, submit a message whose envelope sender and header From use that domain.
- Do not provide a DKIM signature and send from an IP address not authorized by SPF.
- Observe that SPF fails, DKIM does not pass, and Stalwart finds the DMARC policy
reject. - Observe that the DMARC result is nevertheless returned as
dmarc.none, and the spam filter assignsDMARC_NA.
Relevant Log Output
SPF From check failed ... from = "[email protected]", result = SPF check failed (spf.fail)
DKIM verification failed ... result = []
DMARC check failed ... domain = "example.com", policy = "reject", result = No DMARC record (dmarc.none)
Relevant spam-filter result:
DMARC_NA (1.00)
SPF_FAIL (1.00)
VIOLATED_DIRECT_SPF (3.50)
X-Spam-Score: spam, score=10.90
Stalwart Version
v0.16.x
Installation Method
Binary (Linux)
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
Deployment: rootless Podman container on RHEL 9.
Image:
ghcr.io/stalwartlabs/stalwart@sha256:c11546a398589a59271b5685d397a2f291a1da4b896a3c944f0741e124ba5b1c
Image ID:
c65d9ec32478787288d08458764f443d773ae8e653cc4cf9fa721aaa96793f7b
The DMARC TXT records were verified successfully using:
- the host resolver over UDP and TCP;
- the container DNS forwarder over UDP and TCP;
- the authoritative DNS servers;
- DNSSEC validation.
A positive control from Gmail works correctly:
SPF From check passed
DKIM verification passed, domain = "gmail.com"
DMARC check passed, domain = "gmail.com", result = dmarc.pass
The positive-control message also receives DMARC_POLICY_ALLOW (-0.50). Therefore DNS resolution and the positive DMARC path are working; the inconsistent result occurs on the negative DMARC path.
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