NAME

Mail::SPF::Query - query Sender Permitted From for an IP,email,helo

SYNOPSIS

my $query = new Mail::SPF::Query (ip => "127.0.0.1", sender=>'foo@example.com', helo=>"somehost.example.com");
my ($result, $smtp_comment, $header_comment) = $query->result();
my ($guess,  $smtp_guess,   $header_guess)   = $query->best_guess();

if    ($result eq "pass")     { ... } # domain is not forged
elsif ($result eq "fail")     { ... } # domain is forged
else                          {       # domain has not implemented SPF
  if    ($guess eq "pass")    { ... } # result based on $guess_mechs
  elsif ($guess eq "fail")    { ... } # result based on $guess_mechs
  else                        { ... } #
}

The default $guess_mechs is "a/24 mx/24 ptr
       exists:%{p}.wl.trusted-forwarder.org
       exists:%{ir}.wl.trusted-forwarder.org".

ABSTRACT

The SPF protocol relies on sender domains to publish a DNS whitelist of their designated outbound mailers. Given an envelope sender, Mail::SPF::Query determines the legitimacy of an SMTP client IP.

METHODS

Mail::SPF::Query->new()

my $query = eval { new Mail::SPF::Query (ip    =>"127.0.0.1",
                                         sender=>'foo@example.com',
                                         helo  =>"host.example.com") };

optional parameters:
   guess_mechs => "a/24 mx/24 ptr exists:%{p}.wl.trusted-forwarder.org",
   debug => 1, debuglog => sub { print STDERR "@_\n" },
   max_recursion_depth => 10,

if ($@) { warn "bad input to Mail::SPF::Query: $@" }

Set debug=>1 to watch the queries happen.

$query->result()

my ($result, $smtp_comment, $header_comment) = $query->result();

$result will be one of pass, fail, unknown, or error.

pass means the client IP is a designated mailer for the sender. The mail should be accepted subject to local policy regarding the sender.

fail means the client IP is not a designated mailer, and the sender wants you to reject the transaction for fear of forgery.

unknown means the domain either does not publish SPF data or has a configuration error in the published data.

error means the DNS lookup encountered a temporary error during processing.

Results are cached internally for a default of 120 seconds. You can call ->result() repeatedly; subsequent lookups won't hit your DNS.

The smtp_comment should be displayed to the SMTP client.

The header_comment goes into a Received-SPF header.

$query->best_guess()

my ($result, $smtp_comment, $header_comment) = $query->best_guess();

When a domain does not publish SPF records, this library can produce an educated guess anyway.

It pretends the domain defined A, MX, and PTR mechanisms, plus a few others. The default set of directives is

"a/24 mx/24 pt rexists:%{p}.wl.trusted-forwarder.org exists:%{ir}.wl.trusted-forwarder.org"

That default set will return either "pass" or "unknown".

$query->debuglog()

Subclasses may override this with their own debug logger.
I recommend Log::Dispatch.

Alternatively, pass the C<new()> constructor a
C<debuglog => sub { ... }> callback, and we'll pass
debugging lines to that.

EXPORT

None by default.

AUTHOR

Meng Weng Wong, <mengwong+spf@pobox.com>

SEE ALSO

http://spf.pobox.com/