Sender Policy Framework (SPF) is a protocol to indentify qualified servers, which are allowed to send emails on behalf of a domain. It consists of two parts, a DNS TXT record explained in record and a validating mail filter explained in validator. SPF can lead to problems when forwarding mail. For a solution for this see the Sender Rewrite Scheme (SRS) section below.
An example record could look like this
v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.123 a -all and is entered as TXT record of the email sending domain.
The following mechanisms are supported:
|ALL||Matches always; used for a default result like -all for all IPs not matched by prior mechanisms.|
|A||Matches domains A and AAAA record|
|IP4||Matches given IPv4 address or address range|
|IP6||Matches given IPv6 address or address range|
|MX||Matches domains mx record|
|PTR||Matches PTR record. This mechanism is deprecated and should no longer be used.|
|EXISTS||Matches if domain exists, regardless of the address. This is rarely used. Along with the SPF macro language it offers more complex matches like DNSBL-queries.|
|INCLUDE||Includes the SPF record of a given domain|
where you can use the following quantifiers:
|+||PASS result. This can be omitted; e.g., +mx is the same as mx.|
|?||NEUTRAL result interpreted like NONE (no policy).|
|~||SOFTFAIL, a debugging aid between NEUTRAL and FAIL. Typically, messages that return a SOFTFAIL are accepted but tagged.|
|-||FAIL, the mail should be rejected (see below).|
This is shown for Postfix only.
There are several SPF validators available , and can be found in the official Repositories. Below AUR is combined with the mailserver.
/etc/python-policyd-spf/policyd-spf.conf to your needs. An extensively commented version can be found at
Pay some extra attention to the HELO check policy, as standard settings strictly reject HELO failures.
In the main.cf add a timeout for the policyd:
policy-spf_time_limit = 3600s
Then add a transport
policy-spf unix - n n - 0 spawn user=nobody argv=/usr/bin/policyd-spf
Lastly you need to add the policyd to the
smtpd_recipient_restrictions. To minimize load put it to the end of the restrictions:
smtpd_recipient_restrictions= ... permit_sasl_authenticated permit_mynetworks reject_unauth_destination check_policy_service unix:private/policy-spf
You can test your Setup with the following:
defaultSeedOnly = 0
Sender Rewrite Scheme (SRS)
To prevent future SPF checks from failing when forwarding mails, SRS provides a scheme to rewrite the ENVELOPE-FROM field to your own domain, thus passing the SPF test at the recipient server. To prevent creating open relays and still catch and backwrite bounces, this often contains a hash of the original adress combined with a secret only known to the server, providing validability of bounce email. Forinstall AUR and adjust the settings:
SRS_DOMAIN=yourdomain.tld SRS_EXCLUDE_DOMAINS=yourotherdomain.tld,yet.anotherdomain.tld SRS_SEPARATOR== SRS_SECRET=/etc/postsrsd/postsrsd.secret SRS_FORWARD_PORT=10001 SRS_REVERSE_PORT=10002 RUN_AS=postsrsd CHROOT=/usr/lib/postsrsd
Enable and start the daemon, making sure it runs after reboot as well. Then configure postfix accordingly by tweaking the following lines:
sender_canonical_maps = tcp:localhost:10001 sender_canonical_classes = envelope_sender recipient_canonical_maps = tcp:localhost:10002 recipient_canonical_classes= envelope_recipient,header_recipient
Restart postfix and start forwarding mail.
SPF can even be helpful for domains not supposed to send email. Publishing a policy like
v=spfv -all prevents anyone from sending in this domains name thus preventing misuse.
Some contact form providers send mails impersonating the sender using its email address in FROM-field. This is bad practice but still used, and leads to rejected emails with strict SPF policies (such als
v=spf1 a -all).