SPF has a problem with forwarding which appears to be a major barrior to adoption. MTX was created to address it.
Premises:
SPF records are an easy way for the owner of a domain name to list the servers that legitimately send email for their domain. A whitelist. Using their own DNS servers (a single TXT record for each domain and sub-domain).
Block all email without a matching SPF record, and blacklist all spammer domains using SPF, and you block all spam.
I expect blacklisting SPF domains to be much easier than IPs.
It is easy to reject email lacking an SPF match during delivery, so un-forged From: addresses get an error message, and you don't send backscatter to forged addresses.
While the percentage of domains using SPF is still improving, it might be better to use an additional rule in a spam filter (like SpamAssassin) to only slightly increase non-spams which are classified as spam. This is a little more difficult to do with error messages to legitimate senders, but still easy. As of February 2010, 28.7% of my non-spam does not have an SPF record.
meta SPF_NOT_PASS !(SPF_PASS || NO_RELAYS) score SPF_NOT_PASS 4.506 # flag 10% of non-spam that hits this rule as spam. describe SPF_NOT_PASS Not fully validated by SPF.
/etc/spamassassin/local.cf is a good place to put this.
Remember you're blocking all spammer domains with SPF using a domain blacklist.
| Spams without SPF blocked | Non-spams without SPF blocked | SpamAssassin score for SPF_NOT_PASS |
|---|---|---|
| 100% | 28% | 100 |
| 99.92% | 10% | 4.506 |
| 99.52% | 1% | 2.356 |
| 99.15% | 0.1% | 0.285 |
These numbers are estimated from the 97.84% spam accuracy of SpamAssassin and the 73.2% spam accuracy I'm getting due to significantly pre-filtering spam (RBL, greylisting, etc.).
For postfix, in main.cf, add "check_sender_access hash:/etc/postfix/sender_access" to "smtpd_recipient_restrictions =". The format of /etc/postfix/sender_access is one domain per line, "example.com REJECT Domain blacklisted for sending spam."
It is the domain from the SMTP MAIL FROM command that you need to blacklist, often stored in the Return-Path: header. Not the From: address.
Domain name blacklists (bottom of the page) from Jeff Makey
Domain blacklists from spamlinks.net
Postfix syntax:
reject_rhsbl_sender hostkarma.junkemailfilter.com=127.0.0.2
reject_rhsbl_sender block.rhs.mailpolice.com
reject_rhsbl_client block.rhs.mailpolice.com
I'm not using these domain blacklists yet because it's too easy to maintain my own list.
To give error messages only to non-forged sending addresses.
With the Postfix mail server: Spampd as a Before-Queue Content Filter
"I found that with this setup on my sever, SpamAssassin couldn't determine the envelope sender as needed for certain rules (e.g. DNS_FROM_*, NO_DNS_FOR_FROM, SPF_*). I fixed this by passing the --sef (--seh could work as well; but see documentation first) switch to spampd and then adding envelope_sender_header X-Envelope-From to my SpamAssassin config. - JoshuaPettett"
Please create this DNS TXT record for [example.com]:
[insert SPF TXT record]
It won't cause any SPF verification failures because the "?all" indicates the list is incomplete, but it will cause these listed servers to get a "pass" instead of a "none" from SPF verification. Which is good for spam filters that consider email that doesn't get a "pass" more spammy, like mine.
http://www.openspf.org/
| / | beginning of the regex |
| \b | Matches "word boundaries", the point between the whitespace before "src" and the beginning of "src" |
| src | the "src" part of the img tag |
| \s* | any amount of whitespace (spaces, tabs, etc.), or none |
| = | the "=" in the img tag |
| (?:3D)? | quoted printable email encoding can replace an "=" with "=3D", this handles it |
| \s* | any amount of whitespace (spaces, tabs, etc.), or none |
| ["']? | single or double quote, "?" allows for it to be missing |
| cid: | "cid:" the part of an img tag url that replaces http: and means it's an attached file, not hosted on a webserver |
| / | end of the regex |
smtpd_recipient_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unauth_destination
check_client_access cidr:/home/darxus/dnswl/postfix-dnswl-header # add X-DNSWL headers
check_client_access cidr:/home/darxus/dnswl/postfix-dnswl-permit # skip greylisting
check_policy_service inet:127.0.0.1:60000 # greylisting
body_checks = pcre:/etc/postfix/body_checks # image spam regex goes in this file
header RCVD_IN_DNSWL X-DNSWL =~ /^none/ score RCVD_IN_DNSWL -0.1 describe RCVD_IN_DNSWL Sender listed at http://www.dnswl.org/, no trust header RCVD_IN_DNSWL_LOW X-DNSWL =~ /^low/ score RCVD_IN_DNSWL_LOW -1 describe RCVD_IN_DNSWL_LOW Sender listed at http://www.dnswl.org/, low trust header RCVD_IN_DNSWL_MED X-DNSWL =~ /^med/ score RCVD_IN_DNSWL_MED -4 describe RCVD_IN_DNSWL_MED Sender listed at http://www.dnswl.org/, medium trust header RCVD_IN_DNSWL_HI X-DNSWL =~ /^hi/ score RCVD_IN_DNSWL_HI -8 describe RCVD_IN_DNSWL_HI Sender listed at http://www.dnswl.org/, high trust header RCVD_IN_DNSWL_NO X-DNSWL =~ /^No$/ score RCVD_IN_DNSWL_NO 0.1 describe RCVD_IN_DNSWL_NO Sender *not* listed at http://www.dnswl.org/
header RCVD_IN_DNSWL eval:check_rbl('dnswl-firsttrusted', 'list.dnswl.org.')
score RCVD_IN_DNSWL -0.1
describe RCVD_IN_DNSWL Sender listed at http://www.dnswl.org/, no trust
header RCVD_IN_DNSWL_LOW eval:check_rbl_sub('dnswl-firsttrusted', '127.0.\d+.1')
score RCVD_IN_DNSWL_LOW -1
describe RCVD_IN_DNSWL_LOW Sender listed at http://www.dnswl.org/, low trust
header RCVD_IN_DNSWL_MED eval:check_rbl_sub('dnswl-firsttrusted', '127.0.\d+.2')
score RCVD_IN_DNSWL_MED -4
describe RCVD_IN_DNSWL_MED Sender listed at http://www.dnswl.org/, medium trust
header RCVD_IN_DNSWL_HI eval:check_rbl_sub('dnswl-firsttrusted', '127.0.\d+.3')
score RCVD_IN_DNSWL_HI -8
describe RCVD_IN_DNSWL_HI Sender listed at http://www.dnswl.org/, high trust
meta RCVD_IN_DNSWL_NO !RCVD_IN_DNSWL
score RCVD_IN_DNSWL_NO 0.1
describe RCVD_IN_DNSWL_NO Sender *not* listed at http://www.dnswl.org/
spamprobe -H+x-dnswl create-config # needs to be lowercase