Sender Policy Framework (SPF) is a DNS-based email authentication mechanism that helps prevent email spoofing. While SPF records are published in DNS, the actual validation happens at the receiving mail server. A self-hosted SPF validator checks incoming mail against the sender’s published SPF record and assigns a pass/fail/softfail result that your mail server can use to accept, flag, or reject the message.
This guide compares three open-source SPF validation tools for Postfix: pypolicyd-spf, policyd-spf-perl, and spf-engine — each implementing the same protocol but with different performance characteristics, configuration approaches, and feature sets.
How SPF Works
SPF works through DNS TXT records. A domain publishes an SPF record listing the mail servers authorized to send email on its behalf:
| |
When a mail server receives a message claiming to be from user@example.com, it:
- Extracts the envelope sender domain —
example.com - Queries DNS for the SPF record — Looks up the TXT record
- Evaluates the policy — Checks if the connecting IP matches any authorized mechanism
- Returns a result —
pass,fail,softfail,neutral,none, ortemperror
The receiving mail server then uses this result to decide how to handle the message.
Comparison Overview
| Feature | pypolicyd-spf | policyd-spf-perl | spf-engine |
|---|---|---|---|
| Language | Python | Perl | Python |
| License | GPLv2 | Artistic/GPL | MIT |
| GitHub Stars | 180+ (forks) | CPAN package | 45+ |
| Postfix Integration | Policy daemon | Policy daemon | Policy daemon |
| SPFv1 Support | Full | Full | Full |
| RFC 7208 Compliance | Yes | Yes | Yes |
| Skip HELO Check | Configurable | Configurable | Configurable |
| Whitelist Support | Yes (config file) | Yes (config file) | Yes (config file) |
| Rate Limiting | No | No | No |
| Logging | Syslog | Syslog | Syslog |
| Caching | DNS TTL-based | DNS TTL-based | DNS TTL-based |
| Dependencies | pyspf, py3dns | Mail::SPF | pyspf, py3dns |
| Docker Deployment | Custom image | Custom image | Custom image |
| Best For | Python-based mail servers | Perl-based environments | Lightweight Python setup |
pypolicyd-spf
pypolicyd-spf is a Python-based Postfix policy daemon that performs SPF validation. It uses the pyspf library for core SPF evaluation and integrates cleanly with Postfix’s policy delegation protocol.
Docker Compose Configuration
| |
Installation and Configuration
| |
Configuration File (policyd-spf.conf)
| |
Postfix Integration
Add to /etc/postfix/main.cf:
| |
And in /etc/postfix/master.cf:
| |
How pypolicyd-spf Processes Mail
- Postfix receives an incoming SMTP connection and extracts the envelope sender
- Postfix delegates to pypolicyd-spf via the policy service interface
- pypolicyd-spf queries DNS for the sender domain’s SPF record
- The
pyspflibrary evaluates the SPF policy against the connecting IP - pypolicyd-spf returns the result to Postfix (
DUNNO,REJECT, orPREPEND) - Postfix applies the result to the mail handling decision
policyd-spf-perl
policyd-spf-perl is the Perl implementation of a Postfix SPF policy daemon, built on the Mail::SPF CPAN module. It’s the original and most mature SPF validation tool for Postfix, with the widest deployment in production mail servers.
Docker Compose Configuration
| |
Installation
| |
Configuration File
| |
Postfix Integration
Same as pypolicyd-spf — add to main.cf:
| |
And in master.cf:
| |
Key Advantages
- Mature and stable — Deployed in thousands of production mail servers
- Excellent DNS error handling — Graceful handling of DNS timeouts, SERVFAIL, and NXDOMAIN responses
- HELO identity checking — Validates both MAIL FROM and HELO/EHLO identities
- CPAN integration — Easy installation and updates via the Perl package ecosystem
- Well-documented — Extensive man pages and configuration examples
spf-engine
spf-engine is a lightweight Python-based SPF validation engine designed for simplicity and easy integration with Postfix. It follows the same policy daemon protocol as the other tools but with a more minimal codebase and configuration.
Docker Compose Configuration
| |
Dockerfile
| |
Configuration File
| |
Integration with Postfix
| |
SPF Result Actions in Postfix
Once an SPF validator returns a result, you need to decide how Postfix handles it. The typical approach uses postfix-policyd-spf results in header_checks or smtpd_recipient_restrictions:
| |
For stricter enforcement, you can reject messages that fail SPF:
| |
Choosing the Right SPF Validator
Use pypolicyd-spf when:
- Your mail server stack is already Python-based
- You prefer Python for maintenance and customization
- You want good RFC 7208 compliance with a clean codebase
Use policyd-spf-perl when:
- You want the most mature and widely deployed solution
- Your system already has Perl installed (most Linux distributions)
- You need robust DNS error handling and HELO identity checking
- You prefer CPAN-based package management
Use spf-engine when:
- You want the simplest possible Python implementation
- You need a lightweight policy daemon with minimal dependencies
- You’re building a custom mail handling pipeline
Why Self-Host SPF Validation?
Running your own SPF validation gives you control over email filtering policies. Commercial email services (Gmail, Outlook) perform SPF checks internally, but when you host your own mail server, you need to implement validation yourself to protect against spoofing.
SPF is one pillar of email authentication, alongside DKIM (DomainKeys Identified Mail) and DMARC (Domain-based Message Authentication). Together, these three protocols form a defense-in-depth strategy against email spoofing and phishing. SPF validates the envelope sender, DKIM signs the message content, and DMARC ties them together with a published policy.
For organizations running mail servers, SPF validation is essential for compliance with email deliverability best practices. Major mailbox providers increasingly require senders to implement SPF, DKIM, and DMARC — and receivers should validate incoming mail against these standards.
For email security, see our SPF vs DKIM vs DMARC guide. For lightweight SMTP servers, check our Maddy vs Chasquid vs OpenSMTPD comparison. For milter-based mail filtering, our SMTP milter management guide covers advanced mail processing.
FAQ
What’s the difference between SPF pass, fail, and softfail?
- pass — The sending IP is explicitly authorized by the domain’s SPF record (
+allor matching mechanisms) - fail — The sending IP is explicitly NOT authorized (
-all), and the message should be rejected - softfail — The sending IP is likely not authorized (
~all), but the domain owner is not requesting rejection. Mark the message as suspicious but typically still deliver it - neutral — The domain owner makes no assertion (
?all) - none — The domain has no SPF record published
Can SPF validation break legitimate email forwarding?
Yes, this is a known limitation called “SPF breakage.” When email is forwarded through an intermediary server, the connecting IP changes to the forwarder’s IP, which may not be in the original sender’s SPF record. Solutions include: SRS (Sender Rewriting Scheme), which rewrites the envelope sender during forwarding, or using DKIM (which survives forwarding) as the primary authentication method.
Should I reject mail that fails SPF?
It depends on your risk tolerance. Rejecting SPF-fail mail eliminates spoofed messages from that domain but may cause false positives if the domain’s SPF record is misconfigured or if legitimate forwarding is in use. A common approach is to use softfail results to tag messages with a warning header rather than rejecting them outright, then let spam filters use the SPF result as one signal among many.
How do SPF, DKIM, and DMARC work together?
SPF validates the envelope sender (the MAIL FROM address in SMTP). DKIM adds a cryptographic signature to the message header and body. DMARC requires that either SPF or DKIM (or both) align with the From: header visible to the user, and publishes a policy (none, quarantine, or reject) for what receivers should do when alignment fails. All three should be implemented together for comprehensive email authentication.
Do I need SPF validation if I already use Rspamd or SpamAssassin?
Rspamd and SpamAssassin can perform SPF checks as part of their scoring pipeline, but dedicated SPF policy daemons offer more granular control. They allow you to configure per-domain policies, whitelist trusted senders, and return explicit Postfix actions (REJECT, WARN) before the message enters the spam filter. Using both together provides defense-in-depth: the policy daemon for early rejection and the spam filter for comprehensive analysis.
How many DNS lookups does SPF allow?
RFC 7208 limits SPF evaluation to a maximum of 10 DNS lookups. This includes mechanisms like include, a, mx, ptr, exists, and redirect. If a domain’s SPF record requires more than 10 lookups, the result is permerror (permanent error). The all mechanism and modifiers (exp, redirect) do not count toward the lookup limit.