SPFD(8p)
๐ spfd โ bestie edition ๐
okay so listen. this is the manual page for spfd from the 8p section (perl user-contributed docs, we love to see it). it's a whole server. it answers SPF questions. and honestly? iconic. let's get into it ๐ซถ
โจ NAME โจ
spfd โ that's the Mail::SPF one โ a simple forking daemon to provide SPF query services. yeah. she forkin'. she servin'. periodt. ๐
๐ธ VERSION ๐ธ
version 3.20260331
that's the one we're working with, no cap.
๐ฆ SYNOPSIS ๐ฆ
here's how you summon her. three whole moods:
spfd --port|-p port [--set-user|-u uid|username] [--set-group|-g
gid|groupname] [OPTIONS]
spfd --socket|-s filename [--socket-user uid|username] [--socket-group
gid|groupname] [--socket-perms octal-perms] [--set-user|-u uid|username]
[--set-group|-g gid|groupname] [OPTIONS]
spfd --version|-V
spfd --help
TCP mood, UNIX-domain-socket mood, "who even are you" mood, and "help me" mood. all valid. ๐
๐ DESCRIPTION ๐
so spfd is a simple forking Sender Policy Framework (SPF) query server. she receives SPF requests and she answers them, over either a TCP/IP socket or a UNIX domain socket. if you want the whole SPF lore, it's at <https://tools.ietf.org/html/rfc7208>. go read it. i'll wait. ๐
the --port form means she's listening on a TCP/IP socket on the port you hand her. and babes, the default port is 5970. remember that number, you'll need it later. ๐
the --socket form means she's listening on a UNIX domain socket created with the filename you specify. and here's the cute part โ you can give that socket its own user and group ownership with --socket-user and --socket-group, and its own filesystem permissions with --socket-perms. she's got a whole wardrobe. โจ
and generally speaking, spfd can be told โ via --set-user and --set-group โ to drop root privileges and switch to a different user and group before she starts listening for requests. safety first, always. ๐
the --version form prints version info of spfd. the --help form prints usage info for spfd. that's it. that's the whole vibe check.
๐ OPTIONS ๐
spfd takes any of the following OPTIONS:
--default-explanation string,--def-exp stringโ use the givenstringas the default explanation when the authority domain doesn't have an explanation string of its own. backup explanation, bestie. ๐--hostname hostnameโ usehostnameas the host name of the local system instead of, like, auto-detecting it. you know better than the machine, sometimes. ๐--debugโ print out debug info aboutspfd's operation, the incoming requests, and the responses she sends. she's telling you everything. gossip mode: ON. ๐ฃ๏ธ
๐ REQUEST ๐
a request is a series of lines, delimited by \x0A (LF) characters โ or whatever your system considers a newline, we don't judge.
each line has to be of the form option=value. here's what's supported:
versionsโ a comma-separated list of SPF version numbers of SPF records that may be used.1means"v=spf1"records should be used.2means"spf2.0"records should be used. defaults to1,2โ i.e., use any SPF records that are available. records of a higher version are preferred. โจscopeโ the authorization scope of the identity that should be checked. defaults to'mfrom'. the supported scope values are:'helo','mfrom','pra'. for more info, see"new"inMail::SPF::Request. ๐ธidentityโ Required. the sender identity whose authorization should be checked. this is a domain name for the"helo"scope, and an e-mail address for the"mfrom"and"pra"scopes.ip_addressโ Required for checks with the"helo","mfrom", and"pra"scopes. the IP address of the host claiming the identity that's being checked. can be either an IPv4 or an IPv6 address. an IPv4-mapped IPv6 address (e.g.'::ffff:192.168.0.1') is treated as an IPv4 address. noted. ๐helo_identityโ the"HELO"SMTP transaction parameter, in the case that the main identity is of a scope other than"helo". this identity is then used merely for the expansion of"%{h}"macros during the policy evaluation of the main identity. if unspecified with a scope other than"helo", it defaults to"unknown". if the main identity is of the"helo"scope, this option is unused. so like, don't bother. ๐
๐ RESPONSE ๐
spfd responds to SPF requests with a similar series of lines of the form key=value. the most important response keys are:
resultโ the result code of the SPF check:passโ the specified IP address is an authorized SMTP sender for the identity. ๐failโ the specified IP address is not an authorized SMTP sender for the identity. ๐softfailโ the specified IP address is not an authorized SMTP sender for the identity, however the authority domain is still testing out its SPF policy. it's giving "we're figuring it out".neutralโ the identity's authority domain makes no assertion about the status of the IP address. she said nothing. ๐permerrorโ a permanent error occurred while evaluating the authority domain's policy (e.g., a syntax error in the SPF record). manual intervention is required from the authority domain. not your problem, technically. ๐ญtemperrorโ a temporary error occurred while evaluating the authority domain's policy (e.g., a DNS error). try again later. she's just having a moment.noneโ there is no applicable SPF policy for the identity domain. nothing to see here.
local_explanationโ a locally generated explanation of the SPF result.authority_explanationโ the authority domain's explanation for the SPF result.
๐จ bestie, READ THIS ONE: be aware that the authority domain may be a malicious party and thus the authority explanation should not be trusted blindly. see RFC 4408, 10.5, for a detailed discussion of this issue. do NOT trust the strangers on the internet with your whole heart. ๐
โโ๏ธ
received_spf_headerโ an appropriate"Received-SPF"header field for the SPF result. ๐ฌspf_recordโ the authority domain's SPF record that was used for the policy evaluation.
๐ฅ EXAMPLE ๐ฅ
you can test a running spfd using the "netcat" utility, like this (line breaks added for clarity, because we're being nice):
$ echo -e "identity=user@example.com\nip_address=1.2.3.4\n" \
| nc localhost 5970
result=fail
local_explanation=example.com: Sender is not authorized by default to use
'user@example.com' in 'mfrom' identity (mechanism '-all' matched)
authority_explanation=Rejected by SPF record.
received_spf_header=Received-SPF: fail (example.com: Sender is not
authorized by default to use 'user@example.com' in 'mfrom' identity
(mechanism '-all' matched)) receiver=localhost; identity=mfrom;
envelope-from="user@example.com"; client-ip=1.2.3.4
spf_record=v=spf1 mx -all
look at her go. so clean. so functional. obsessed. ๐โจ
๐ COMPATIBILITY ๐
spfd has undergone the following interface changes compared to earlier versions. lore drop time:
2.000
- a new preferred request style has been introduced. instead of the old
"sender"request option โ which was specific to the"MAIL FROM"SMTP identity โ a generic"identity"option should now be specified. plus, a"scope"option may be given to specify the identity's scope, otherwise a scope of"mfrom"is assumed. and the old"ip"and"helo"options have been replaced by the"ip_address"and"helo_identity"options, respectively. glow-up fr fr. ๐
this is how legacy requests with the "mfrom" scope would translate to the new preferred request style:
Legacy request style | New request style
----------------------------+---------------------------------------
| scope=mfrom
sender=<mfrom-identity> | identity=<mfrom-identity>
ip=<ip-address> | ip_address=<ip-address>
helo=<helo-identity> | helo_identity=<helo-identity>
a new response style featuring new response values has also been introduced:
Legacy response style | New response style
----------------------------+---------------------------------------
result=<result-code> | result=<result-code>
header_comment=<local-exp> | local_explanation=<local-exp>
smtp_comment=<local-exp | authority_explanation=<authority-exp>
or authority-exp> |
spf_record=<spf-record> | spf_record=<spf-record>
| received_spf_header=<header>
the legacy request style is deprecated but still supported for backwards compatibility. the legacy response values are still returned for backwards compatibility in addition to the new response values, but may be removed in the future. adjust your code to use the new request and response styles. don't get caught lacking when they delete it. ๐
- the former
"unknown"and"error"result codes have been renamed to"permerror"and"temperror", respectively, in order to comply with RFC 4408 terminology. rebranded. โจ - in the case of an empty
"MAIL FROM"SMTP transaction parameter ("MAIL FROM:<>"), the identity checked will bepostmaster@helo nameas specified in RFC 7208. ๐ฎ
๐ง SEE ALSO ๐ง
Mail::SPFspfquery(1)- <http://tools.ietf.org/html/rfc4408>
go read your homework, bestie. ๐
๐ AUTHORS ๐
this version of spfd is a complete rewrite by Julian Mehnle <julian@mehnle.net>, based on an earlier version written by Meng Weng Wong <mengwong+spf@pobox.com>.
give them their flowers, they earned them. ๐๐ซถ
and that's the whole page, babes. this was SPFD(8p), perl v5.40.1, dated 2026-04-05 โ she ate, she slayed, she forked. goodnight and go configure something responsibly. ๐
๐๐ธ
๐ฆ where this page comes from
- ubuntu stonking: spf-tools-perl 3.20260331-1 ยท BSD-3-Clause
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms