Bootstrap FreeKB - Postfix (Email) - Enable SPF (Sender Policy Framework)
Postfix (Email) - Enable SPF (Sender Policy Framework)

Updated:   |  Postfix (Email) articles

SPF is the abbreviation for Sender Policy Framework. SPF is used for outgoing email (emails sent from your email system to some recipient) to allow or deny the outgoing email based on certain rules, to prevent email spoofing.

SPF can be helpful in ensuring your domain does not get black listed, which ultimately is helpful in ensuring emails sent from your domain get delivered to recipients inbox.

You will probably also want to enable DKIM (DomainKeys Identified Mail). Check out my article Docker mailserver enable DKIM.

If you are on a Debian distribution (Mint, Ubuntu), you should be able to install the SPF package using apt-get.

sudo apt-get install postfix-policyd-spf-python postfix-pcre

 

If you are on a Red Hat distribution (CentOS, Fedora, Red Hat), you will probably first need to install the EPEL (Extra Packages for Enterprise Linux) repository. And then you should be able to install the SPF package using the dnf install or yum install command. This should default to using Python version 2.x.x.

dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf install pypolicyd-spf.noarch

 

Or, if you'd like to use Python version 3.x.x.

pip3 install pypolicyd-spf
pip3 install pyspf
pip3 install py3dns
pip3 install ipaddr

 

Update /etc/python-policyd-spf/policyd-spf.conf, changing HELO_reject and Mail_From_reject from Fail to False. This will make it so that emails are not rejected.

debugLevel = 1
defaultSeedOnly = 1

#HELO_reject = Fail
HELO_reject = False
#Mail_From_reject = Fail
Mail_From_reject = False

PermError_reject = False
TempError_Defer = False

skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1

 

Line 1 of shows that /usr/bin/python is being used.

~]$ head -1 /usr/libexec/postfix/policyd-spf
#!/usr/bin/python

 

Ensure the /usr/bin/python --version command returns the Python version.

~]$ /usr/bin/python --version
Python 2.7.18

 

The policyd-spf command with the -h flag can be used to ensure the policyd-spf command is working.

~]$ /usr/libexec/postfix/policyd-spf -h
usage: policyd-spf [<configfilename>]

 

And then the policyd-spf command followed by the absolute path to the policyd-spf.conf file can be used to test.

~]$ /usr/libexec/postfix/policyd-spf /etc/python-policyd-spf/policyd-spf.conf

 

When prompted, enter something like this.

request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
helo_name=p-impout004.msg.pkvw.co.charter.net
queue_id=8045F2AB23
sender=<senders email address>
recipient=<recipient email address>
client_address=<senders IP address>
client_name=john.doe

 

If the request is allowed by SPF, something like this should be displayed.

action=prepend Received-SPF: Pass (sender SPF authorized) 
identity=mailfrom; 
client-ip=47.43.26.135; 
helo=p-impout004.msg.pkvw.co.charter.net; 
envelope-from=jane.doe@new.rr.com; 
receiver=john.doe@example.com

 

Append the following to the bottom of /etc/postfix/master.cf.

  • In this example, "/usr/bin/python" is used because line 1 of /usr/libexec/postfix/policyd-spf has /usr/bin/python
  • In this example, "/usr/libexec/postfix/policyd-spf" is used since the locate command returned "/usr/libexec/postfix/policyd-spf"
policyd-spf  unix  -       n       n       -       0       spawn
   user=nobody argv=/usr/bin/python /usr/libexec/postfix/policyd-spf /etc/python-policyd-spf/policyd-spf.conf

 

Add the following directive to /etc/postfix/main.cf to set the SPF timeout and to skip SPF checking for local email. permit_mynetworks should be listed before the check_policy_service unix:private/policyd-spf and permit directives to successfully skip SFP checking for local email. Additionally, the check_policy_service unix:private/policyd-spf and permit directives must be listed after the reject_unauth_destination directive.

policyd-spf_time_limit = 3600

smtpd_recipient_restrictions = permit_mynetworks,
                               reject_unauth_destination,
                               check_policy_service unix:private/policyd-spf,
                               permit

 

Add the following MX and TXT record to the DNS server that resolves your Postfix hostname. In this example, the records are for Postfix with hostname mail.example.com.

mail         IN     MX    1 mail.example.com.
example.com. IN    TXT    "v=spf1 mx ~all"

 

Or like this. The include directive is used to specify the domain (example.com) that email can be sent from.

mail         IN     MX    1 mail.example.com.
example.com. IN    TXT    "v=spf1 a mx include:example.com ~all"

 

The dig command can then be used to see if DNS contains SPF.

~]$ dig mail.example.com txt

;; QUESTION SECTION:
;mail.example.com.        IN      TXT

;; ANSWER SECTION
example.com.      86400   IN      TXT     "v=spf1 mx ~all"

 

Restart Postfix.

systemctl restart postfix

 

With debugLevel = 4 in /etc/python-policyd-spf/policyd-spf.conf, you should see something like this in /var/log/maillog.

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: spfcheck: pyspf result: "['None', '', 'helo']"

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: None; identity=helo; client-ip=192.30.252.201; helo=smtp.outlook.com; envelope-from=noreply@outlook.com; receiver=john.doe@example.com

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: Header type: SPF; Authres ID (for AR): None

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: spfcheck: pyspf result: "['Pass', 'sender SPF authorized', 'mailfrom']"

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: Pass; identity=mailfrom; client-ip=192.30.252.201; helo=smtp.outlook.com; envelope-from=noreply@outlook.com; receiver=john.doe@example.com

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: Header type: SPF; Authres ID (for AR): None

Dec 27 06:26:17 ip-172-31-19-227 policyd-spf[22502]: Action: prepend: Text: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.30.252.201; helo=smtp.outlook.com; envelope-from=noreply@outlook.com; receiver=john.doe@example.com

Dec 27 06:26:18 ip-172-31-19-227 policyd-spf[22502]: Normal exit

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter e3c3a9 in the box below so that we can be sure you are a human.