App-Qmail-DMARC
view release on metacpan or search on metacpan
bin/qmail-dmarc view on Meta::CPAN
}
my $message = MailX::Qmail::Queue::Message->receive
or die "Invalid message\n";
$SIG{__DIE__} = sub {
debug died => "@_" unless $^S;
die @_;
};
my $envelope_from = $message->from;
debug 'RFC5321.MailFrom' => $envelope_from;
debug to => join ', ', $message->to;
if ( exists $ENV{RELAYCLIENT} ) {
debug RELAYCLIENT => "$ENV{TCPREMOTEHOST} [$ENV{TCPREMOTEIP}]";
}
else {
my $dkim = Mail::DKIM::Verifier->new;
$dkim->PRINT( $message->body =~ s/\cM?\cJ/\cM\cJ/gr );
$dkim->CLOSE;
debug 'DKIM result' => $dkim->result;
if ( $dkim->result ne 'pass' ) {
debug 'Remote IP' => $ENV{TCPREMOTEIP};
my %spf_query = ( ip_address => $ENV{TCPREMOTEIP} );
debug helo => $spf_query{helo_identity} = $message->helo;
my $header_from = $message->header_from;
my $header_from_domain;
if ($header_from) {
debug 'RFC5322.From' => $spf_query{identity} =
$header_from->address;
$header_from_domain = $header_from->host;
$spf_query{scope} = 'mfrom';
}
else {
$spf_query{scope} = 'helo';
}
my $spf_result = spf_query(%spf_query);
debug 'SPF result' => $spf_result;
$message->add_header( $spf_result->received_spf_header );
my $dmarc_text = (
my $dmarc_result = Mail::DMARC::PurePerl->new(
source_ip => $ENV{TCPREMOTEIP},
envelope_to => domain( ( $message->to )[0] ),
if_set( envelope_from => domain($envelope_from) ),
if_set( header_from => $header_from_domain ),
dkim => $dkim,
spf => {
if_set( domain => $header_from_domain ),
scope => $spf_query{scope},
result => $spf_result->code,
},
)->validate
)->result;
debug 'DMARC result' => $dmarc_text;
$message->add_header("DMARC-Status: $dmarc_text");
if ( $dmarc_result->result ne 'pass' ) {
my $disposition = $dmarc_result->disposition;
debug 'DMARC disposition' => $disposition;
reject 'Failed DMARC test.' if $disposition eq 'reject';
}
}
}
delete $ENV{QMAILQUEUE}; # use original qmail-queue
$message->send == 0 or die "Error sending message: exit status $?\n";
debug action => 'queue';
END {
debug 'exit code' => $?;
say STDERR "$FindBin::Script\[$$]: " . join '; ', @debug;
}
__END__
=head1 NAME
qmail-dmarc - verify using DMARC and queue a mail message for delivery
=head1 DESCRIPTION
qmail-dmarc is designed to be called by qmail-smtpd instead of qmail-queue
and will verify if incoming e-mail conforms to the DMARC policy of its
sender domain:
=over 4
=item 1.
If the environment variable C<RELAYCLIENT> exists, no verification is done,
and the e-mail is immediately passed to C<qmail-queue>.
=item 2.
In any other case, we check if the message contains a valid DKIM signature
matching the domain of the C<From:> header field.
If this is the case, the e-mail is passed to C<qmail-queue>.
=item 3.
If not, a SPF check is done, and a C<Received-SPF:> header field is added to
the message.
Then we check if the message is aligned with its sender's DMARC policy.
A C<DMARC-Status:> header field is added.
If the message does not align to the policy, the policy advises to reject such
messages and when the environment variable C<DMARC_REJECT> is set to a true
value, the message will be rejected with C<554 Failed DMARC test.>
=item 4.
In any other case the message is passed on to C<qmail-queue>.
( run in 2.068 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )