TIL: SPF, DKIM, and DMARC, and how to set rejection rules based solely on DKIM - eviltoast

I host my own e-mail server, and for a long time I have been pulling my hair out on why the receiving end will still accept e-mails sent from my domain without any DKIM signature.

I have made sure that DKIM has been setup properly in my server, which means if an outgoing e-mail either fails the DKIM test, or doesn’t contain any DKIM signature, then the e-mail must be fake. But currently while the receiving end knows to reject if DKIM=fail, it lets the e-mail pass if there is no DKIM signature.

Problem: I found as long as someone impersonates my e-mail account then send an e-mail that will pass the SPF test and doesn’t contain any DKIM signature (real or fake), then it will still be considered legitimate by the recipient email server. This is even more problematic in my case as I have to rely on an e-mail relay provided by my ISP to send e-mails out (my ISP specifically blocks any outgoing port 25 connections, apparently to fight spam). This unfortunately means any other customers of the same ISP can potentially send e-mails on my behalf as long as they leave any DKIM signature out on purpose.

Solution: I just discovered the way DMARC works is by passing e-mail that passes EITHER SPF or DKIM check. The keyword is ‘OR’, and ‘EITHER’. So to make sure the receiving end checks only for DKIM validity, turns out all I had to do was to make sure SPF never passes or fails. In other words, SPF always returning neutral would mean DKIM would now become the only factor. Since either one of the two must show ‘pass’, and now SPF will always return as ‘neutral’, then DKIM must pass in order for DMARC to pass. i.e. DKIM can no longer be ‘neutral’ (aka no signature) let alone fail.

The way to set SPF to always return neutral is to set the TXT record to be: v=spf1 ?all

Now as long as your DMARC is set properly, unauthorized e-mails as determined by the DKIM outcome of either “fail” or “none” (aka neutral, or no signature) will always be rejected. Simple as that. Problem solved.

Source: https://serverfault.com/questions/1014250/can-i-set-dmarc-to-tell-receiver-to-fail-if-no-dkim-signature-provided-in-email/1041210#1041210