Configuring Sender Policy Framework (SPF) on qmail

March 15, 2020 by Roberto Puzzanghera 16 comments

The Sender Policy Framework (SPF) is an open standard specifying a technical method to prevent sender address forgery. More precisely, the current version of SPF — called SPFv1 or SPF Classic — protects the envelope sender address, which is used for the delivery of messages. See the box on the right for a quick explanation of the different types of sender addresses in e-mails.

First of all you have to setup your SPF record. You can create it using this great wizard. Basically it will turn to be something like:

yourdomain.tld. IN TXT "v=spf1 mx a ip4:<your-ip>/32 ip4:<your-localnet>/24 include:alloweddomain.tld -all"

If your mx domain also appears in the name server's DMZ (DeMilitarized Zone) you should add such a TXT record in there as well, otherwise you will be exposed to spoofing, as spammers can always send you mail messages with your domain in the envelope.

It is important to have an SPF record also for the control/me domain, as the system messages like bounces and so on are sent with the null sender, and the remote MTA will use that domain for the SPF check.

The SPF behavior of your mail server is controlled by the file /var/qmail/control/spfbehavior. You can specify a value between 0 and 6:

  • 0 disabled (Default). Never do SPF lookups, don't create Received-SPF headers
  • 1 selects 'annotate-only' mode,  where  qmail-smtpd  will  annotate  incoming  email with Received-SPF fields, but will not reject any messages. 
  • 2 will produce temporary failures on DNS lookup problems so you can make sure you always have meaningful Received-SPF headers. 
  • 3 selects  'reject'  mode,  where  incoming  mail  will be rejected if the SPF record says 'fail'. 
  • 4 selects a more stricter rejection mode, which is like 'reject' mode, except that incoming mail will also be rejected when the SPF record says 'softfail'. 
  • 5 will also reject when the SPF record says 'neutral'
  • 6 if no SPF records are available at all (or a syntax error was encountered).

You can override the value in /var/qmail/control/spfbehavior by setting the SPFBEHAVIOR environment variable (typically in /etc/tcprules.d/tcp.smtp or, if you’ve used these notes as your guide, in ~/vpopmail/etc/tcp.smtp).

Values higher than 3 are strongly discouraged. You probably will want to go with 2 or 3.

Adding local rules to create exceptions

If you have problems with clients failing the SPF and you want to allow them, you can save local rules into a line in control/spfrules. These rules will be evaluated in advance.

include:domain.tld ip4:111.222.333.444 ip4:192.168.0.1/24

Testing

First of all, check the header of your incoming messages. For email senders who don’t have SPF enabled, you should find a Received-SPF header that looks something like this:

Received-SPF: none (0: domain at xxxxxxxxxx does not designate permitted sender hosts)

For email senders who have SPF enabled, you’ll see a header that looks something like this:

Received-SPF: pass(0: SPF record at xxxxxxxxxx designates x.x.x.x as permitted sender)

To run a rejection test, use the highest value (6 ) and restart qmail. Then, from a remote IP address, try telnetting into your mail server and sending a message using a fake email address:

> telnet qmail.yourserver.net 25
Trying [remote-IP]...
Connected to [remote-IP].
Escape character is '^]'.
220 qmail.yourserver.net ESMTP
mail from: test@nospfdomain.net
250 ok
rcpt to: user@yourdomain.net
550 See http://spf.pobox.com/why.html?sender=test%40nospfdomain.net&ip=[sender-IP]&receiver=0 (#5.7.1)
quit
221 qmail.yourserver.net
Connection closed by foreign host.

Remember to restore to 2 or 3 your /var/qmail/control/spfbehavior file.

Comments

SPF Headers Missing for IPv6

Hi Roberto , 

     Just wanted to check , whenever a mail is received from a ipv6 host the spf headers in the received mail dont show any ip details or spf status .  Below is the header 

Received: from mail-pl1-x62e.google.com (2607:f8b0:4864:20::62e)
Received-SPF: unknown (mail.example.com: No IP address in conversation)

While the sending domain does have the above ipv6 block in the spf record. 

/var/qmail/control/spfbehavior is 3

Am i missing something in my config. 

Reply |

SPF Headers Missing for IPv6

this qmail is not IPv6 compliant and the SPF feature is no exception...

Reply |

SPF Headers Missing for IPv6

Strange , well I have smtpd / smtpsd and submission all working on both ipv4 and ipv6 interfaces .  As we have a dual stack network with ipv4 and ipv6 both enabled on our clients.  The default prefered is ipv6  and I had been using in this way for the past 2+ years.  I start the smtpd / smtpsd and submission in the following way 

smtpd   ( Note the : before 0 below it tells to listen on both ipv4 and ipv6)

exec /usr/local/bin/softlimit -m "$SOFTLIMIT" \
/usr/local/bin/tcpserver -v -R -l "$LOCAL" \
-x $TCPRULES_DIR/tcp.smtp.cdb -c "$MAXSMTPD" \
-u "$QMAILDUID" -g "$NOFILESGID" :0 25 \
$QMAILDIR/bin/qmail-smtpd /bin/true 2>&1

smtpsd  ( Note the : before 0 below it tells to listen on both ipv4 and ipv6)

exec /usr/local/bin/softlimit -m "$SOFTLIMIT" \
/usr/local/bin/sslserver -seV -Rp -l "$LOCAL" \
-Xx $TCPRULES_DIR/tcp.smtp.cdb -c "$MAXSMTPD" \
-u "$QMAILDUID" -g "$NOFILESGID" :0 smtps \
$QMAILDIR/bin/qmail-smtpd ~vpopmail/bin/vchkpw /bin/true 2>&1

And Finally submission  ( Note the : before 0 below it tells to listen on both ipv4 and ipv6) as below

exec /usr/local/bin/softlimit -m "$SOFTLIMIT" \
/usr/local/bin/tcpserver -v -R -l "$LOCAL" \
-x $TCPRULES_DIR/tcp.submission.cdb -c "$MAXSMTPD" \
-u "$QMAILDUID" -g "$NOFILESGID" :0 587 \
$QMAILDIR/bin/qmail-smtpd \
~vpopmail/bin/vchkpw /bin/true 2>&1

When you said earlier that this qmail is not IPv6 compliant and the SPF feature is no exception... did you mean that it wont work with IPv6 at all. 

Also maybe you can add the :0 part in the qmail configuring guide for those who want it on both ipv4 and ipv6. Also as we have dovecot working on both ipv4 and ipv6 as per your guide and the doveconf -n output.

Do let me know your suggesstions as I am not an expert in the subject matter but happenned to figure out the above via a few trial and error methods . 

Cheers

Reply |

SPF Headers Missing for IPv6

Hi Shailendra,

when I say that my qmail is not ipv6 compliant it exactly means that it doesn't handle ipv6 addresses.

On the other hand, tcpserver and sslserver have been upgraded by Erwin Hoffmann and both of them work well with ipv6. The options that you mentioned are NOT qmail options, but tcpserver and/or sslserver options. But once the comunication is in qmail-smtpd's hands, it cannot handle the ipv6 address. So all features that have to do with the remote IP are lost.

Do you have RBL working with ipv6 there? It would be interesting to know if it manages to work...

I am closing communications for ipv6 here, in order to force remote clients to use ipv4 only

Reply |

SPF Headers Missing for IPv6

HI Roberto , 

    Thanks a lot for clearing my doubts.  Yes I do have rbl working with ipv6  below are the logs . 

2025-04-20 11:04:13.141847367 qmail-smtpd[654048]: rbl: ip=2a01:111:f403:2414::729 query=2a01:111:f403:2414::729.b.barracudacentral.org result=ignore message=''
2025-04-20 11:04:13.159437376 qmail-smtpd[654048]: rbl: ip=2a01:111:f403:2414::729 query=2a01:111:f403:2414::729.zen.spamhaus.org result=ignore message=''
2025-04-20 11:04:13.399191460 qmail-smtpd[654048]: rbl: ip=2a01:111:f403:2414::729 query=2a01:111:f403:2414::729.psbl.surriel.com result=ignore message=''
2025-04-20 11:04:13.647677775 qmail-smtpd[654048]: rbl: ip=2a01:111:f403:2414::729 query=2a01:111:f403:2414::729.bl.spamcop.net result=ignore message=''

I will dig futher with the archive logs and update you if I find anything interesting with rbl and ipv6.

Regards

Reply |

SPF Headers Missing for IPv6

good to know. Thank's for letting me know

Reply |

SPF Headers Missing for IPv6

Well I did dig a bit and first of all sorry for doubting the guide .  While going through the logs and the dmarc reports received from various providers  it was noticed that all the reports contained only the ipv4 ip of the server hinting towards only the ipv4 functionality of the qmail-smtpd .  Though it would be interesting to see qmail to function on ipv6 also in near future . It is such a good piece of software . 

Cheers

Reply |

http://spf.pobox.com doesn't exist

Finally , I'm back with SPF
I'm doing some test and I found that the URL in the error message dosen't work !

Any idea ?

host -t a spf.pobox.com
Host spf.pobox.com not found: 3(NXDOMAIN)

Reply |

http://spf.pobox.com doesn't exist

I think I've fixed this in June 30 patch. Are you using the latest patch?

Reply |

http://spf.pobox.com doesn't exist

Sorrryyyyy !!!
I missed the last 2 patchs !!!
To mucho work !

Sorry !

Reply |

SPF not rejecting messages

Hi

After a lot of work, finally I have SPF "working"
The incoming emails are marked by SPF, but setting spfbehavior on 3 ,4,5 or 6, the message is not rejected
The emails has the spf header, but not rejection

Received-SPF: fail (xx4.xxx.net: SPF record at 1.co does not designate xxx.xxx.xxx.xxx as permitted sender)

What i'm mising ?
spfbehavior has 644 qmaild qmail permission

Can I debug spf ?

Txs 
Pablo Murillo

Reply |

SPF not rejecting messages

Hi, don't you have messages like this in your log?

2023-08-23 02:58:14.340365586 qlogenvelope: result=rejected code=550 reason=spf detail=fail helo=junma.biz mailfrom=xxxxxx@junma.biz

try to test sending yourself a mail with that domain as sender. It has a a bad spf record which fails also with spfbehaviour=3

Reply |

SPF not rejecting messages

Hi
I was working with other stuff and I forget completly SPF
Now I'm back, and now I don't see the headers any more !
Ajajaja
I re-compile but, nothing
I'm completly lost
I will check everything again !

Reply |

SPF not rejecting messages

I have spfbehaviour with 644 root.root privileges

I suggest using strace against qmail-smtpd to see what's going on 

Reply |

SPF not rejecting messages

openat(AT_FDCWD,"control/spfbehavior",O_RDONLY|O_NONBLOCK,00) = 4 (0x4)

read(4,"3\n",64) = 2 (0x2)

close(4) = 0 (0x0)

openat(AT_FDCWD,"control/spfrules",O_RDONLY|O_NONBLOCK,00) = 4 (0x4)

read(4,"include:spf.trusted-forwarder.or"...,64) = 34 (0x22)

close(4) = 0 (0x0)

openat(AT_FDCWD,"control/spfguess",O_RDONLY|O_NONBLOCK,00) ERR#2 'No such file or directory'

openat(AT_FDCWD,"control/spfexp",O_RDONLY|O_NONBLOCK,00) ERR#2 'No such file or directory'

Reply |

SPF not rejecting messages

It seems ok..

Reply |