3.20261105 2026-11-06 Australia/Melbourne
** Thanks to Giovanni <g.bechis@snb.it> for these changes:
- RFC 7208 says there MUST be a limit of no more than 10 MX records
looked up and checked; throw a permerror when the limit is exceeded
instead of silently truncating the list
- RFC 7208 says implementations SHOULD limit "void lookups" to two;
enable the corresponding regression tests
- Ensure every module's $VERSION is set by Dist::Zilla at release time,
and manage the version number in README the same way
- Security: escape untrusted text in the Received-SPF header to
prevent header field injection:
- escape parentheses and backslashes in the explanation comment,
so text from a malformed SPF record or the sender identity can
no longer close the comment early and inject forged fields such
as client-ip=
- escape control characters (e.g. CR/LF) in the envelope-from and
helo fields
- Fix macro expansion stopping at the first line break in a macro
string, leaving later macros unexpanded
- Security: authority_explanation now escapes control and non-ASCII
characters in the explanation string (exp= TXT record) published in
DNS, and document that the result text() may contain untrusted data
- Remove the check for includes of the same domain through CNAME
aliases. Including a domain and a CNAME alias of it is legal in
RFC 7208, but the check tried to throw a hard fail for it. With
a real resolver it read an unpopulated Net::DNS internal field and
so in practice did nothing, but where it did take effect (e.g.
with Net::DNS::Resolver::Programmable) it could wrongly fail
authorized senders, and it used CNAME targets from DNS as
unescaped regular expressions, which could make process() die.
It also made an extra CNAME lookup per include that was not
counted towards the RFC 7208 DNS lookup and void lookup limits.
The test suite's resolver now follows CNAMEs, which is what the
RFC 7208 cname-aliasing test case needed
- Security: an exception thrown by the DNS resolver, including
Net::DNS refusing to compose a query for an invalid domain name,
made the SPF result none, i.e. no policy, rather than temperror.
As invalid names can come from macros expanded with the sender's
local part or HELO name, a sender could turn a domain's -all
policy into none. Invalid domain names (empty label, label longer
than 63 bytes, or name longer than 253 bytes, counted the way
Net::DNS does, i.e. in bytes of UTF-8 and reading escapes such as
"\.") are now treated as non-existent without querying the
resolver, per RFC 7208, and other resolver exceptions result in
temperror
- Check the IP address version in the ip6 mechanism using the public
NetAddr::IP API, rather than enumerating the request's address via
an overloaded array dereference and reading an internal field,
which died if the request's IP address was a large network
- Allow Mail::SPF::Server->process() to evaluate a proposed SPF record
passed in via a new 'record' option, instead of querying DNS for the
authority domain's record, so a not-yet-published record can be tested
against real DNS state
- Prefer SPF1 over SPF2 (Sender ID, which is deprecated) when a record
could be parsed as either
- When a domain publishes both "v=spf1" and "spf2.0" records, always
select the "v=spf1" record. Previously the record was chosen by the
order of the records in the DNS answer, so the result could vary
between queries, although the documentation and RFC 4406 said
"spf2.0" records were preferred. Sender ID is historic (RFC 6686),
so "v=spf1" is now deliberately preferred
- Security: a "p" macro in an explanation string (exp= TXT record)
made a PTR look-up and up to 10 A/AAAA look-ups for every
occurrence, not limited by the RFC 7208 DNS look-up limits, so a
sender could make a single SPF check send thousands of DNS
queries. The "p" macro value is now looked up at most once per SPF
check and authority domain. Also, exceeding the void look-up limit
while expanding the explanation made authority_explanation() die;
it now falls back to the default explanation
- Reject a network (e.g. '10.0.0.0/8') as a request's ip_address
with an EInvalidOptionValue exception. NetAddr::IP accepted it,
which made no sense for SPF and changed the meaning of the
mechanisms' address checks
- Ignore an explanation string (exp= TXT record) that contains
anything other than printable ASCII characters and spaces, as
RFC 7208 requires, and use the default explanation instead.
Control characters were already escaped, but an MTA using the
explanation in an SMTP reply would still have sent the escaped
text of a malicious explanation
- Return none without querying DNS when the identity's domain is
empty (e.g. "MAIL FROM:<a@>", which queried the root zone) or a
single-label name (e.g. "HELO mailhost", which the resolver may
expand with its search list and so query the receiver's internal
domains), as RFC 7208 requires
- Security: spfd now escapes control characters in the values of
its response, so text from DNS or the client cannot add lines to
the response, and in its debug output
- Security: fix spfd's privilege dropping with --set-user and
--set-group. An unknown user or group name was not reported (due to
an operator precedence bug) and could leave spfd running as root,
the invoking user's supplementary groups (e.g. root's) were kept,
and --set-user without --set-group kept group ID 0. spfd now dies on
unknown names, drops the supplementary groups when started as root,
and changes to the user's primary group if no group is given
- Security: limit spfd to 64 concurrent connections, 60 seconds per
connection, and 32 request lines of at most 1024 bytes, so a local
client can no longer exhaust the process table or memory with idle,
slow or overlong requests. A request still being processed after 60
seconds (e.g. because DNS servers are unreachable) gets a temperror
result. spfd now also logs non-Mail::SPF errors
for a request, and no longer runs the child's code in the listening
process if fork() fails
- Security: spfd now creates its UNIX socket accessible to its owner
only until --socket-user, --socket-group and --socket-perms have
been applied, so other users can't connect to it in the meantime.
Fix --socket-group being ignored unless --socket-user was also
given (a typo compared the socket path instead of the group), and
die with a clear message if the listening socket can't be created
- Security: spfquery now opens the --file argument in explicit read
mode. A file name ending in "|" was run as a shell command, and one
starting with ">" truncated the file
3.20260331 2026-04-01 Australia/Melbourne
** Thanks to Giovanni <g.bechis@snb.it> for this change:
- Do not check for multiple CNAMEs if the included domain is a macro
3.20250505 2025-05-05 Australia/Sydney
** Thanks to Giovanni <g.bechis@snb.it> for these changes:
- avoid a 'Attempt to reload Mail/SPF/Mech.pm aborted.' error
- remove empty record structure in order to stringify it correctly
** Thanks to Keith <kealanta@fastmailteam.com> for these changes, based on Debian patches:
- Redirecting all references to openspf.org to open-spf.org
- fix pod test errors
3.20240923 2024-09-23 Australia/Melbourne
- Fix issue where certain DNS results would cause an exception to be thrown
3.20240827 2024-08-27 Australia/Melbourne
** Thanks to Giovanni <g.bechis@snb.it> for the changes in this release.
- Do not try to parse an IPv4 address unnecessarily
- Import RFC7208 Tests
- referencing the same TXT record through multiple CNAME aliases is not permitted
by RFC7208
- Make it clear that BlackMagic module is not available
- Fix checks for IPv4-mapped IPv6 connections
- Cache DNS results
- Misc dzil/build/ci improvements
- SPF explanation text is restricted to 7-bit ascii
3.20240617 2024-06-17 Australia/Melbourne
- Update INSTALL file for Dist::Zilla changes
Thanks to Giovanni <g.bechis@snb.it>
- Fix memory leak in Mail::SPF::Server when cacheing a Mail::SPF::MacroString
Thanks to Giovanni <g.bechis@snb.it> and Felipe Gasper
- When mfrom is empty, create a synthetic mfrom (postmaster@helo) and check
that identity using the mfrom scope as specified in RFC7208
Thanks to Giovanni <g.bechis@snb.it>
- Fix missing declare in Mail::SPF::Server
Thanks to Giovanni <g.bechis@snb.it>
- require Mail::SPF::Mech when needed
Thanks to Giovanni <g.bechis@snb.it>
- correctly handle empty labels
Thanks to Giovanni <g.bechis@snb.it>
- use "try" instead of "eval"
Thanks to Giovanni <g.bechis@snb.it>
- error out if the lookup fails
Thanks to Giovanni <g.bechis@snb.it>
3.20240206 2024-02-06 UTC
- Remove signature file from distribution
3.20240205 2024-02-05 UTC
- Fix pod in Mail::SPF::Util (RT#93241)
Thanks to rwfranks@acm.org and GBECHIS@cpan.org
- Fixes char_str_list is not a valid sub in new Net::DNS (RT#149825)
Reworked from patch supplied with thanks by GBECHIS@cpan.org
- BREAKING CHANGE: spfd is now installed in /bin instead of /sbin
As a result Mail::SPF now respects an install prefix and may be
more easily installed in a non root and/or local lib environment.
--- 2.009 (2013-07-21 03:30)
Mail::SPF:
* Default to querying only TXT type RRs (query_rr_types = Mail::SPF::Server->
query_rr_type_txt). Experience has shown that querying SPF type RRs is
impractical.
--- 2.008 (2012-01-30 08:15)
Mail::SPF:
* Sanitize result local_explanation (as well as result object string
representation) by replacing all non-printable or non-ascii characters
with their hex-escaped representation (e.g., "\x00").
(Addresses: bugs.launchpad.net #806926)
Miscellaneous:
* Change openspf.org URLs to openspf.net because openspf.org is unreachable
indefinitely.
* Change <http://www.ietf.org/rfc/….txt> URLs
to <http://tools.ietf.org/html/…>.
* META.yml: configure_requires: Module::Build 0.2805
* META.yml: requires: Net::DNS 0.62 (was: 0.52) (Closes: rt.cpan.org #28545)
* META.yml: Revert to flat version numbers for perl and Net::DNS::Resolver::
Programmable build requirements to avoid Module::Build::Compat/Makefile.PL
incompatibilities. (Closes: rt.cpan.org #53231)
* Attempt to prevent a cascading failure in t/00.03-class-result.t that seems
to happen under rare, unknown circumstances. (Closes: rt.cpan.org #39099)
Debian:
* Declare Debian source package format as 3.0.
* Standards-Version: 3.9.2 (was: 3.8.3)
* Bump debhelper compatibility level to 7 (was: 5) and simplify debian/rules
using debhelper 7 features.
* debian/control: Simplify depdendencies under the assumption that package
will be installed on Debian Lenny (oldstable at the time of writing) or
later (or the Ubuntu equivalent).
* debian/watch: Use dist-based URL.
--- 2.007 (2009-10-31 21:00)
Mail::SPF:
* Macro expansion:
* Distinguish between split and join delimiters; they are not necessarily
the same.
* Support multiple split delimiters rather than at most one.
Miscellaneous:
* We ship and pass the 2009.10 release of the official RFC 4408 test suite.
* Give advice in INSTALL on how to install without root privileges.
Debian:
* Standards-Version: 3.8.3 (was: 3.8.0)
* Build-Depends-Indep: perl-modules (>= 5.10.0) | libmodule-build-perl (>= 0.26)
(was: libmodule-build-perl (>= 0.26))
--- 2.006 (2008-08-17 22:00)
Mail::SPF:
+ Added result object factory facility to Mail::SPF::Server in order to
support the sub-classing of Mail::SPF::Server and Mail::SPF::Result.
See README for details.
Any code throwing Mail::SPF::Result(::*) objects directly should stop doing
so and use Mail::SPF::Server::throw_result() instead.
+ Added a "query_rr_types" option to Mail::SPF::Server's constructor as a
way to disable the retrieval of either "SPF" or "TXT" type RRs.
I wouldn't make use of it if I was you!
! Changed the "max_void_dns_lookups" option's default value from undef (i.e.,
no limit) to a limit of 2. This should not cause any problems in practice,
however see the "max_void_dns_lookups" option's description for specifics
on what this entails.
* Match <toplabel> patterns greedily by reversing the order of the <toplabel>
regexp alternatives from RFC 4408. Thus TLDs with dashes (e.g.,
".xn--wgv71a") are now correctly matched.
* In macro strings, expand '%-' to '%20' rather than '-'.
Thanks to Frank Ellermann for providing a test case for the RFC 4408 test
suite that inadvertently exposed this bug.
> Mail::SPF::Result:
+ Added new received_spf_header_name() constant specifying the "Received-
SPF" header field name, which may (and usually should) be overridden by
custom result sub-classes; see the documentation.
* Generate "identity=mailfrom" rather than "identity=mfrom" in
"Received-SPF" header field.
* name() now returns a symbolic result name instead of the trailing part of
the result class name. This should have no impact on 3rd-party code.
* Added new isa_by_name() method as an equivalent to the built-in isa(),
taking a result name instead of a class name. Provides a superset of the
is_code() method's functionality.
* Substituted ";"s for "&" parameter separators in the openspf.org "Why?"
page URL in the default authority explanation string. This change is
purely cosmetic.
* Minor documentation fixes and improvements.
Miscellaneous:
* We ship and pass the 2008.08 release of the official RFC 4408 test suite.
* While officially declaring a build-requirement of Module::Build >= 0.2805
(which, if not satisfied, Module::Build itself will warn about, but not
abort), do not strictly require it. If the META.yml file generated during
package building is irrelevant, e.g., if we are being built by a package
management/build system such as Debian's, then 0.26 is sufficient.
* Recommend NetAddr::IP >= 4.007, as it has all $& and $` removed for better
performance;
see <http://issues.apache.org/SpamAssassin/show_bug.cgi?id=5312>.
--- 2.005 (2007-05-30 23:00)
Mail::SPF:
+ Added a "max_void_dns_lookups" option to Mail::SPF::Server's constructor,
allowing the number of potentially abusive lookups induced by DoS attacks
to be limited. See the documentation of the Mail::SPF::Server class.
+ Added a "precedence" class property to Mail::SPF::GlobalMod and sub-classes
that defines the order in which global modifiers are to be processed
(0: first, 1: last). See Mail::SPF::Mod.
Mail::SPF::Mod::Exp has precedence 0.2, Mail::SPF::Mod::Redirect has 0.8.
Also, Mail::SPF::Record::global_mods() now returns modifiers ordered by
precedence.
+ Added support for a non-standard %{_scope} pseudo macro that expands to the
request's identity scope. Note: Do NOT use any such non-standard macros in
explanation strings published in DNS!
! Mail::SPF::Util::valid_domain_for_ip_address() now requires a Mail::SPF::
Request object to be passed as a new second argument. This is actually
consistent with many of Mail::SPF's methods. Please excuse the late API
change (but who uses Mail::SPF::Util directly anyway?).
* Updated default authority explanation string to include identity scope in
the openspf.org "Why?" page URL in order to avoid misleading result
explanations.
* Truncate labels resulting from macro expansions to 63 bytes. This is not
strictly required by RFC 4408, 8.1/27, but is merely meant as a precaution.
* Minor documentation fixes and improvements.
Miscellaneous:
* We ship and pass the 2007.05 release of the official RFC 4408 test suite
(no changes were required).
! Build-require Module::Build >= 0.2805 (was: >= 0.26), hopefully fixing a
version.pm/CPAN.pm compatibility issue (closes: rt.cpan.org #26784).
(Debian packaging is not affected because it does not rely on META.yml.)
Debian:
* Conflicts: spfquery (<< 1.2.5.dfsg-1) (was unversioned)
--- 2.004 (2007-01-20 02:00)
Mail::SPF:
* Correctly fall back to default authority explanation if the authority
domain does specify an explanation string but it cannot be expanded (e.g.
due to syntax errors).
* In Mail::SPF::Result::received_spf_header(), gracefully fall back to a
hostname of "unknown" if a fully qualified hostname can not be determined.
Some (misconfigured) systems simply will not reveal one.
* Minor documentation improvements and fixes.
Miscellaneous:
* Note in the README file that we pass the 2006.11 release of the official
RFC 4408 test-suite.
Tests:
* Do not test Mail::SPF::Util::hostname(), as some (misconfigured) systems
simply will not reveal a fully qualified hostname (see CPANTS tests for
2.003).
* Minor code clean-up.
--- 2.003 (2007-01-10 00:00)
Mail::SPF:
* Fixed two Perl 5.6 incompatibilities:
* Added `use utf8` statements in several modules to keep Perl 5.6 from
whining about /[\p{}]/.
* Do not use the `use constant { a=>1, b=>2 }` multiple-constants idiom,
as it was introduced only in constant 1.03 (Perl 5.7.2).
* Fixed a very minor bug where a "TempError" result would incorrectly be
returned in the very rare case when the SPF-type look-up succeeded but
returned 0 records, and the following TXT-type look-up errored or timed
out. Now a "None" result is correctly returned in that case as demanded
by RFC 4408.
spfquery:
* Minor documentation fixes.
--- 2.002 (2006-12-14 00:00)
Mail::SPF:
* Updated default authority explanation string to the SPF website's new
"Why?" page URL parameters scheme:
<http://www.openspf.org/Why?id=%{S}&ip=%{I}&receiver=%{R}>
spfquery:
* Updated the '--help' text and man-page with regard to the black magic
options (which require the yet unreleased Mail::SPF::BlackMagic module).
--- 2.001 (gold release) (2006-12-09 20:00)
Gold Release!
Major overhaul:
! Major code refactoring, achieving full RFC 4408/4406 compliance, and
breaking API compatibility with 2.000.
! Switched from ExtUtils::MakeMaker to Module::Build.
+ Added complete rewrites of spfquery (2.500) and spfd (2.000).
+ Added complete documentation.
+ Added unit tests and the RFC 4408 test-suite.
+ Added Debian package control files.
+ And more... (closes: rt.cpan.org #20821, #20822, #21922, #21925)
--- 2.000 (initial release) (2005-06-23 00:00)
# $Id: CHANGES 61 2013-07-22 03:45:15Z julian $
# vim:syn= tw=79 sts=2 sw=2
Keyboard Shortcuts
Global
s
Focus search bar
?
Bring up this help dialog
GitHub
gp
Go to pull requests
gi
Go to GitHub issues (only if GitHub is preferred repository)