Skip to content
Simon Arlott edited this page Oct 5, 2023 · 2 revisions

Q1304

Question

How do I use Mail::SPF instead of libspf2 for SPF lookups?

Answer

Use the following Perl script:

use Mail::SPF;

sub spf {
	my $primary_hostname = Exim::expand_string('$primary_hostname');
	my $sender_address, $sender_host_address, $sender_helo_name;

	if (@_) {
		$sender_host_address = shift;
		$sender_address = shift;
		$sender_helo_name = shift;
	} else {
		$sender_host_address = Exim::expand_string('$sender_host_address');
		$sender_address = Exim::expand_string('$sender_address');
		$sender_helo_name = Exim::expand_string('$sender_helo_name');
	}

	my $identity = length($sender_address) ? $sender_address : $sender_helo_name;

	if (!length($identity) || !length($sender_host_address)) {
		return 'invalid:';
	}

	my $server = Mail::SPF::Server->new(
		hostname => $primary_hostname,
		max_dns_interactive_terms => 50,
		max_void_dns_lookups => undef,
	);
	my $request = Mail::SPF::Request->new(
		scope => length($sender_address) ? 'mfrom' : 'helo',
		identity => $identity,
		ip_address => $sender_host_address,
		helo_identity => $sender_helo_name,
	);
	my $result = $server->process($request);

	return $result->code . ':' . ($result->received_spf_header =~ s/:/::/gr);
}

This can be used in an ACL as follows:

warn
    set acl_m_spf_result = ${perl{spf}}
    set acl_m_spf_header = ${listextract{2}{$acl_m_spf_result}}
    set acl_m_spf_result = ${listextract{1}{$acl_m_spf_result}}

Use $acl_m_spf_result instead of $spf_result and $acl_m_spf_header instead of $spf_received.

To check the result, use ${if inlist{$acl_m_spf_result}{...}} instead of spf = ..., e.g.:

deny condition ${if inlist{$acl_m_spf_result}{fail}}

Clone this wiki locally