The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

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/