| Current File : //usr/local/share/man/man3/Mail::SPF::Query.3 |
.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.30)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{
. if \nF \{
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "Mail::SPF::Query 3"
.TH Mail::SPF::Query 3 "2006-02-27" "perl v5.20.0" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
Mail::SPF::Query \- query Sender Policy Framework for an IP,email,helo
.SH "VERSION"
.IX Header "VERSION"
1.999.1
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 6
\& my $query = new Mail::SPF::Query (ip => "127.0.0.1", sender=>\*(Aqfoo@example.com\*(Aq, helo=>"somehost.example.com", trusted=>0, guess=>0);
\& my ($result, # pass | fail | softfail | neutral | none | error | unknown [mechanism]
\& $smtp_comment, # "please see http://www.openspf.org/why.html?..." when rejecting, return this string to the SMTP client
\& $header_comment, # prepend_header("Received\-SPF" => "$result ($header_comment)")
\& $spf_record, # "v=spf1 ..." original SPF record for the domain
\& ) = $query\->result();
\&
\& if ($result eq "pass") { "Domain is not forged. Apply RHSBL and content filters." }
\& elsif ($result eq "fail") { "Domain is forged. Reject or save to spambox." }
.Ve
.SH "ABSTRACT"
.IX Header "ABSTRACT"
The \s-1SPF\s0 protocol relies on sender domains to describe their designated outbound
mailers in \s-1DNS. \s0 Given an email address, Mail::SPF::Query determines the
legitimacy of an \s-1SMTP\s0 client \s-1IP\s0 address.
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
There are two ways to use Mail::SPF::Query. Your choice depends on whether the
domains your server is an \s-1MX\s0 for have secondary MXes which your server doesn't
know about.
.PP
The first and more common style, calling \->\fIresult()\fR, is suitable when all mail
is received directly from the originator's \s-1MTA. \s0 If the domains you receive do
not have secondary \s-1MX\s0 entries, this is appropriate. This style of use is
outlined in the \s-1SYNOPSIS\s0 above. This is the common case.
.PP
The second style is more complex, but works when your server receives mail from
secondary MXes. This performs checks as each recipient is handled. If the
message is coming from a valid \s-1MX\s0 secondary for a recipient, then the \s-1SPF\s0 check
is not performed, and a \*(L"pass\*(R" response is returned right away. To do this,
call \f(CW\*(C`result2()\*(C'\fR and \f(CW\*(C`message_result2()\*(C'\fR instead of \f(CW\*(C`result()\*(C'\fR.
.PP
If you do not know what a secondary \s-1MX\s0 is, you probably don't have one. Use
the first style.
.PP
You can try out Mail::SPF::Query on the command line with the following
command:
.PP
.Vb 3
\& perl \-MMail::SPF::Query \-le \*(Aqprint for Mail::SPF::Query\->new(
\& helo => shift, ipv4 => shift, sender => shift)\->result\*(Aq \e
\& helohost.example.com 1.2.3.4 user@example.com
.Ve
.SH "BUGS"
.IX Header "BUGS"
Mail::SPF::Query tries to implement the \s-1SPF\s0 specification (see \*(L"\s-1SEE ALSO\*(R"\s0)
as close as reasonably possible given that M:S:Q has been the very first \s-1SPF\s0
implementation and has changed with the \s-1SPF\s0 specification over time. As a
result, M:S:Q has various known deficiencies that cannot be corrected with
reasonably little effort:
.IP "\(bu" 4
\&\fBUnable to query \s-1HELO\s0 and \s-1MAIL FROM\s0 separately.\fR M:S:Q is not designed to
support the \fIseparate\fR querying of the \s-1HELO\s0 and \s-1MAIL FROM\s0 identities. Passing
the \s-1HELO\s0 identity as the \f(CW\*(C`sender\*(C'\fR argument for a stand-alone \s-1HELO\s0 check might
generally work but could yield unexpected results.
.IP "\(bu" 4
\&\fBNo IPv6 support.\fR IPv6 is not supported. \f(CW\*(C`ip6\*(C'\fR mechanisms in \s-1SPF\s0 records
and everywhere else are simply ignored.
.IP "\(bu" 4
\&\fBResult explanation may be inappropriate for local policy results.\fR If a
query result was caused by anything other than a real \s-1SPF\s0 record (i.e. local
policy, overrides, fallbacks, etc.), and no custom \f(CW\*(C`default_explanation\*(C'\fR was
specified, the domain's explanation or M:S:Q's hard-coded default explanation
will still be returned. Be aware that in this case the explanation may not
correctly explain the reason for such an artificial result.
.SH "NON-STANDARD FEATURES"
.IX Header "NON-STANDARD FEATURES"
Also due to its long history, M:S:Q does have some legacy features that are not
parts of the official \s-1SPF\s0 specification, most notably \fIbest guess processing\fR
and \fItrusted forwarder accreditation checking\fR. Please be careful when using
these \fInon-standard\fR features or when reproducing them in your own \s-1SPF\s0
implementation, as they may cause unexpected results.
.SH "METHODS"
.IX Header "METHODS"
.ie n .SS """Mail::SPF::Query\->new()"""
.el .SS "\f(CWMail::SPF::Query\->new()\fP"
.IX Subsection "Mail::SPF::Query->new()"
.Vb 4
\& my $query = eval { new Mail::SPF::Query (
\& ip => \*(Aq127.0.0.1\*(Aq,
\& sender => \*(Aqfoo@example.com\*(Aq,
\& helo => \*(Aqhost.example.com\*(Aq,
\&
\& # Optional parameters:
\& debug => 1, debuglog => sub { print STDERR "@_\en" },
\& local => \*(Aqextra mechanisms\*(Aq,
\& trusted => 1, # do trusted forwarder processing
\& guess => 1, # do best guess if no SPF record
\& default_explanation => \*(AqPlease see http://spf.my.isp/spferror.html for details\*(Aq,
\& max_lookup_count => 10, # total number of SPF includes/redirects
\& sanitize => 0, # do not sanitize all returned strings
\& myhostname => \*(Aqfoo.example.com\*(Aq, # prepended to header_comment
\& override => { \*(Aqexample.net\*(Aq => \*(Aqv=spf1 a mx \-all\*(Aq,
\& \*(Aq*.example.net\*(Aq => \*(Aqv=spf1 a mx \-all\*(Aq },
\& fallback => { \*(Aqexample.org\*(Aq => \*(Aqv=spf1 a mx \-all\*(Aq,
\& \*(Aq*.example.org\*(Aq => \*(Aqv=spf1 a mx \-all\*(Aq }
\& ) };
\&
\& if ($@) { warn "bad input to Mail::SPF::Query: $@" }
.Ve
.PP
Set \f(CW\*(C`trusted=>1\*(C'\fR to turned on \f(CW\*(C`trusted\-forwarder.org\*(C'\fR accreditation
checking. The mechanism \f(CW\*(C`include:spf.trusted\-forwarder.org\*(C'\fR is used just
before a \f(CW\*(C`\-all\*(C'\fR or \f(CW\*(C`?all\*(C'\fR. The precise circumstances are somewhat more
complicated, but it does get the case of \f(CW\*(C`v=spf1 \-all\*(C'\fR right \*(-- i.e.
\&\f(CW\*(C`trusted\-forwarder.org\*(C'\fR is not checked. \fBThis is a non-standard feature.\fR
.PP
Set \f(CW\*(C`guess=>1\*(C'\fR to turned on automatic best guess processing. This will
use the best_guess \s-1SPF\s0 record when one cannot be found in the \s-1DNS. \s0 Note that
this can only return \f(CW\*(C`pass\*(C'\fR or \f(CW\*(C`neutral\*(C'\fR. The \f(CW\*(C`trusted\*(C'\fR and \f(CW\*(C`local\*(C'\fR flags
also operate when the best_guess is being used. \fBThis is a non-standard
feature.\fR
.PP
Set \f(CW\*(C`local=>\*(Aqinclude:local.domain\*(Aq\*(C'\fR to include some extra processing just
before a \f(CW\*(C`\-all\*(C'\fR or \f(CW\*(C`?all\*(C'\fR. The local processing happens just before the
trusted forwarder processing. \fBThis is a non-standard feature.\fR
.PP
Set \f(CW\*(C`default_explanation\*(C'\fR to a string to be used if the \s-1SPF\s0 record does not
provide a specific explanation. The default value will direct the user to a
page at www.openspf.org with the following message:
.PP
.Vb 1
\& Please see http://www.openspf.org/why.html?sender=%{S}&ip=%{I}&receiver=%{R}
.Ve
.PP
Note that the string has macro substitution performed.
.PP
Set \f(CW\*(C`sanitize\*(C'\fR to 0 to get all the returned strings unsanitized.
Alternatively, pass a function reference and this function will be used to
sanitize the returned values. The function must take a single string argument
and return a single string which contains the sanitized result.
.PP
Set \f(CW\*(C`debug=>1\*(C'\fR to watch the queries happen.
.PP
Set \f(CW\*(C`override\*(C'\fR to define \s-1SPF\s0 records for domains that do publish but which you
want to override anyway. Wildcards are supported. \fBThis is a non-standard
feature.\fR
.PP
Set \f(CW\*(C`fallback\*(C'\fR to define \*(L"pretend\*(R" \s-1SPF\s0 records for domains that don't publish
them yet. Wildcards are supported. \fBThis is a non-standard feature.\fR
.PP
Note: domain name arguments to override and fallback need to be in all
lowercase.
.ie n .SS """$query\->result()"""
.el .SS "\f(CW$query\->result()\fP"
.IX Subsection "$query->result()"
.Vb 1
\& my ($result, $smtp_comment, $header_comment, $spf_record, $detail) = $query\->result();
.Ve
.PP
\&\f(CW$result\fR will be one of \f(CW\*(C`pass\*(C'\fR, \f(CW\*(C`fail\*(C'\fR, \f(CW\*(C`softfail\*(C'\fR, \f(CW\*(C`neutral\*(C'\fR, \f(CW\*(C`none\*(C'\fR,
\&\f(CW\*(C`error\*(C'\fR or \f(CW\*(C`unknown [...]\*(C'\fR:
.ie n .IP """pass""" 4
.el .IP "\f(CWpass\fR" 4
.IX Item "pass"
The client \s-1IP\s0 address is an authorized mailer for the sender. The mail should
be accepted subject to local policy regarding the sender.
.ie n .IP """fail""" 4
.el .IP "\f(CWfail\fR" 4
.IX Item "fail"
The client \s-1IP\s0 address is not an authorized mailer, and the sender wants you to
reject the transaction for fear of forgery.
.ie n .IP """softfail""" 4
.el .IP "\f(CWsoftfail\fR" 4
.IX Item "softfail"
The client \s-1IP\s0 address is not an authorized mailer, but the sender prefers that
you accept the transaction because it isn't absolutely sure all its users are
mailing through approved servers. The \f(CW\*(C`softfail\*(C'\fR status is often used during
initial deployment of \s-1SPF\s0 records by a domain.
.ie n .IP """neutral""" 4
.el .IP "\f(CWneutral\fR" 4
.IX Item "neutral"
The sender makes no assertion about the status of the client \s-1IP.\s0
.ie n .IP """none""" 4
.el .IP "\f(CWnone\fR" 4
.IX Item "none"
There is no \s-1SPF\s0 record for this domain.
.ie n .IP """error""" 4
.el .IP "\f(CWerror\fR" 4
.IX Item "error"
The \s-1DNS\s0 lookup encountered a temporary error during processing.
.ie n .IP """unknown [...]""" 4
.el .IP "\f(CWunknown [...]\fR" 4
.IX Item "unknown [...]"
The domain has a configuration error in the published data or defines a
mechanism that this library does not understand. If the data contained an
unrecognized mechanism, it will be presented following \*(L"unknown\*(R". You should
test for unknown using a regexp \f(CW\*(C`/^unknown/\*(C'\fR rather than \f(CW\*(C`eq "unknown"\*(C'\fR.
.PP
Results are cached internally for a default of 120 seconds. You can call
\&\f(CW\*(C`\->result()\*(C'\fR repeatedly; subsequent lookups won't hit your \s-1DNS.\s0
.PP
\&\f(CW\*(C`smtp_comment\*(C'\fR should be displayed to the \s-1SMTP\s0 client.
.PP
\&\f(CW\*(C`header_comment\*(C'\fR goes into a \f(CW\*(C`Received\-SPF\*(C'\fR header, like so:
.PP
.Vb 1
\& Received\-SPF: $result ($header_comment)
.Ve
.PP
\&\f(CW\*(C`spf_record\*(C'\fR shows the original \s-1SPF\s0 record fetched for the query. If there is
no \s-1SPF\s0 record, it is blank. Otherwise, it will start with \f(CW\*(C`v=spf1\*(C'\fR and
contain the \s-1SPF\s0 mechanisms and such that describe the domain.
.PP
Note that the strings returned by this method (and most of the other methods)
are (at least partially) under the control of the sender's domain. This means
that, if the sender is an attacker, the contents can be assumed to be hostile.
The various methods that return these strings make sure that (by default) the
strings returned contain only characters in the range 32 \- 126. This behavior
can be changed by setting \f(CW\*(C`sanitize\*(C'\fR to 0 to turn off sanitization entirely.
You can also set \f(CW\*(C`sanitize\*(C'\fR to a function reference to perform custom
sanitization. In particular, assume that \f(CW\*(C`smtp_comment\*(C'\fR might contain a
newline character.
.PP
\&\f(CW\*(C`detail\*(C'\fR is a hash of all the foregoing result elements, plus extra data
returned by the \s-1SPF\s0 result.
.PP
\&\fIWhy the weird duplication?\fR In the beginning, \f(CW\*(C`result()\*(C'\fR returned only one
value, the \f(CW$result\fR. Then \f(CW$smtp_comment\fR and \f(CW$header_comment\fR came
along. Then \f(CW$spf_record\fR. Past a certain number of positional results, it
makes more sense to have a hash. But we didn't want to break backwards
compatibility, so we just declared that the fifth result would be a hash and
future return value would go in there.
.PP
The keys of the hash are:
.PP
.Vb 6
\& result
\& smtp_comment
\& header_comment
\& header_pairs
\& spf_record
\& modifiers
.Ve
.ie n .SS """$query\->result2()"""
.el .SS "\f(CW$query\->result2()\fP"
.IX Subsection "$query->result2()"
.Vb 1
\& my ($result, $smtp_comment, $header_comment, $spf_record) = $query\->result2(\*(Aqrecipient@domain\*(Aq, \*(Aqrecipient2@domain\*(Aq);
.Ve
.PP
\&\f(CW\*(C`result2()\*(C'\fR does everything that \f(CW\*(C`result()\*(C'\fR does, but it first checks to see if
the sending system is a recognized \s-1MX\s0 secondary for the recipient(s). If so,
then it returns \f(CW\*(C`pass\*(C'\fR and does not perform the \s-1SPF\s0 query. Note that the
sending system may be a \s-1MX\s0 secondary for some (but not all) of the recipients
for a multi-recipient message, which is why result2 takes an argument list.
See also \f(CW\*(C`message_result2()\*(C'\fR.
.PP
\&\fBThis is a non-standard feature.\fR \fBThis feature is also deprecated, because
exemption of trusted relays, such as secondary MXes, should really be performed
by the software that uses this library before doing an \s-1SPF\s0 check.\fR
.PP
\&\f(CW$result\fR will be one of \f(CW\*(C`pass\*(C'\fR, \f(CW\*(C`fail\*(C'\fR, \f(CW\*(C`neutral [...]\*(C'\fR, or \f(CW\*(C`unknown\*(C'\fR.
See \f(CW\*(C`result()\*(C'\fR above for meanings.
.PP
If you have secondary MXes and if you are unable to explicitly white-list them
before \s-1SPF\s0 tests occur, you can use this method in place of \f(CW\*(C`result()\*(C'\fR,
calling it as many times as there are recipients, or just providing all the
recipients at one time.
.PP
\&\f(CW\*(C`smtp_comment\*(C'\fR can be displayed to the \s-1SMTP\s0 client.
.PP
For example:
.PP
.Vb 3
\& my $query = new Mail::SPF::Query (ip => "127.0.0.1",
\& sender=>\*(Aqfoo@example.com\*(Aq,
\& helo=>"somehost.example.com");
\&
\& ...
\&
\& my ($result, $smtp_comment, $header_comment);
\&
\& ($result, $smtp_comment, $header_comment) = $query\->result2(\*(Aqrecip1@example.com\*(Aq);
\& # return suitable error code based on $result eq \*(Aqfail\*(Aq or not
\&
\& ($result, $smtp_comment, $header_comment) = $query\->result2(\*(Aqrecip2@example.org\*(Aq);
\& # return suitable error code based on $result eq \*(Aqfail\*(Aq or not
\&
\& ($result, $smtp_comment, $header_comment) = $query\->message_result2();
\& # return suitable error if $result eq \*(Aqfail\*(Aq
\& # prefix message with "Received\-SPF: $result ($header_comment)"
.Ve
.ie n .SS """$query\->message_result2()"""
.el .SS "\f(CW$query\->message_result2()\fP"
.IX Subsection "$query->message_result2()"
.Vb 1
\& my ($result, $smtp_comment, $header_comment, $spf_record) = $query\->message_result2();
.Ve
.PP
\&\f(CW\*(C`message_result2()\*(C'\fR returns an overall status for the message after zero or
more calls to \f(CW\*(C`result2()\*(C'\fR. It will always be the last status returned by
\&\f(CW\*(C`result2()\*(C'\fR, or the status returned by \f(CW\*(C`result()\*(C'\fR if \f(CW\*(C`result2()\*(C'\fR was never
called.
.PP
\&\f(CW$result\fR will be one of \f(CW\*(C`pass\*(C'\fR, \f(CW\*(C`fail\*(C'\fR, \f(CW\*(C`neutral [...]\*(C'\fR, or \f(CW\*(C`error\*(C'\fR. See
\&\f(CW\*(C`result()\*(C'\fR above for meanings.
.ie n .SS """$query\->best_guess()"""
.el .SS "\f(CW$query\->best_guess()\fP"
.IX Subsection "$query->best_guess()"
.Vb 1
\& my ($result, $smtp_comment, $header_comment) = $query\->best_guess();
.Ve
.PP
When a domain does not publish an \s-1SPF\s0 record, this library can produce an
educated guess anyway.
.PP
It pretends the domain defined A, \s-1MX,\s0 and \s-1PTR\s0 mechanisms, plus a few others.
The default set of directives is
.PP
.Vb 1
\& a/24 mx/24 ptr
.Ve
.PP
That default set will return either \*(L"pass\*(R" or \*(L"neutral\*(R".
.PP
If you want to experiment with a different default, you can pass it as an
argument: \f(CW\*(C`$query\->best_guess("a mx ptr")\*(C'\fR
.PP
\&\fBThis is a non-standard feature.\fR \fBThis method is also deprecated.\fR You
should set \f(CW\*(C`guess=>1\*(C'\fR on the \f(CW\*(C`new()\*(C'\fR method instead.
.ie n .SS """$query\->trusted_forwarder()"""
.el .SS "\f(CW$query\->trusted_forwarder()\fP"
.IX Subsection "$query->trusted_forwarder()"
.Vb 1
\& my ($result, $smtp_comment, $header_comment) = $query\->best_guess();
.Ve
.PP
It is possible that the message is coming through a known-good relay like
\&\f(CW\*(C`acm.org\*(C'\fR or \f(CW\*(C`pobox.com\*(C'\fR. During the transitional period, many legitimate
services may appear to forge a sender address: for example, a news website may
have a \*(L"send me this article in email\*(R" link.
.PP
The \f(CW\*(C`trusted\-forwarder.org\*(C'\fR domain is a white-list of known-good hosts that
either forward mail or perform benign envelope sender forgery:
.PP
.Vb 1
\& include:spf.trusted\-forwarder.org
.Ve
.PP
This will return either \*(L"pass\*(R" or \*(L"neutral\*(R".
.PP
\&\fBThis is a non-standard feature.\fR \fBThis method is also deprecated.\fR You
should set \f(CW\*(C`trusted=>1\*(C'\fR on the \f(CW\*(C`new()\*(C'\fR method instead.
.ie n .SS """$query\->sanitize(\*(Aqstring\*(Aq)"""
.el .SS "\f(CW$query\->sanitize(\*(Aqstring\*(Aq)\fP"
.IX Subsection "$query->sanitize(string)"
This applies the sanitization rules for the particular query object. These
rules are controlled by the \f(CW\*(C`sanitize\*(C'\fR parameter to the c<\fInew()\fR> method.
.ie n .SS """strict_sanitize(\*(Aqstring\*(Aq)"""
.el .SS "\f(CWstrict_sanitize(\*(Aqstring\*(Aq)\fP"
.IX Subsection "strict_sanitize(string)"
This ensures that all the characters in the returned string are printable. All
whitespace is converted into spaces, and all other non-printable characters are
converted into question marks. This is probably over-aggressive for many
applications.
.PP
This function is used by default when the \f(CW\*(C`sanitize\*(C'\fR option is passed to the
\&\f(CW\*(C`new()\*(C'\fR method.
.PP
\&\fBThis function is not a class method.\fR
.ie n .SS """$query\->debuglog()"""
.el .SS "\f(CW$query\->debuglog()\fP"
.IX Subsection "$query->debuglog()"
Subclasses may override this with their own debug logger. \f(CW\*(C`Log::Dispatch\*(C'\fR is
recommended.
.PP
Alternatively, pass the \f(CW\*(C`new()\*(C'\fR constructor a \f(CW\*(C`debuglog => sub { ... }\*(C'\fR
callback, and we'll pass debugging lines to that.
.SH "WARNINGS"
.IX Header "WARNINGS"
Mail::Query::SPF should only be used at the point where messages are received
from the Internet. The underlying assumption is that the sender of the e\-mail
is sending the message directly to you or one of your secondary MXes. If your
\&\s-1MTA\s0 does not have an exhaustive list of secondary MXes, then the \f(CW\*(C`result2()\*(C'\fR
and \f(CW\*(C`message_result2()\*(C'\fR methods can be used. These methods take care to
permit mail from secondary MXes.
.SH "AUTHORS"
.IX Header "AUTHORS"
Meng Weng Wong <mengwong+spf@pobox.com>, Philip Gladstone, Julian Mehnle
<julian@mehnle.net>
.SH "SEE ALSO"
.IX Header "SEE ALSO"
About \s-1SPF: \s0<http://www.openspf.org>
.PP
Mail::SPF::Query: <http://search.cpan.org/dist/Mail\-SPF\-Query>
.PP
The latest release of the \s-1SPF\s0 specification: <http://www.openspf.org/spf\-classic\-current.txt>