NAME
Mail::MIMEDefang::Async - Asynchronous I/O engine for MIMEDefang external checks
DESCRIPTION
Mail::MIMEDefang::Async provides concurrent DNS, socket-based, and process-based checks for use in MIMEDefang filter callbacks. All checks share a single AnyEvent event loop and the call blocks until every check has completed or the global timeout fires.
Requires the optional modules AnyEvent, AnyEvent::DNS, AnyEvent::Socket, and AnyEvent::Util from CPAN.
METHODS
- md_async_init(%opts)
-
Initialise the async engine. Call once per process (e.g. at the top of your mimedefang-filter, after
use Mail::MIMEDefang::Async).Options:
max_concurrency Max parallel checks in flight (default: 10) global_timeout Hard wall-clock limit for the whole batch (default: 10s) dns_timeout Per-DNS-query timeout (default: 5s) socket_timeout Per-socket-connection timeout (default: 5s) - md_async_run_checks(\@checks)
-
Run a list of check descriptors concurrently. Blocks until all checks complete or the global timeout fires. Returns
{ results => \%r, errors => \%e }.Each check is a hashref with
name,type('dns','socket', or'process'), andargs. Use Mail::MIMEDefang::Async::Checks to build them. - md_async_relay_is_blacklisted($addr, $zone)
-
Async drop-in replacement for
relay_is_blacklistedfrom Mail::MIMEDefang::Net.Looks up
reverse_ip($addr).$zoneas a DNS A record. Returns the first matching IP string on a listing,0if not listed, orundefon error/timeout. - md_async_email_is_blacklisted($email, $zone, $hash_type)
-
Async drop-in replacement for
email_is_blacklistedfrom Mail::MIMEDefang::Net.Hashes
$emailusing MD5 or SHA1 (controlled by$hash_type), then looks up$hash.$zone. Returns the first matching IP string,0if not listed, orundefon error/timeout. - md_async_spf_verify($mail, $relayip, $helo)
-
Async-enhanced replacement for
md_spf_verifyfrom Mail::MIMEDefang::SPF.Pre-fetches the sender domain's SPF TXT record via the async engine, then evaluates it using Mail::SPF synchronously. Returns the same values as
md_spf_verify. Returnsundefimmediately ifMail::SPFis not installed. - md_async_dmarc_verify($domain)
-
Async replacement for
md_get_dmarc_recordfrom Mail::MIMEDefang::Net.Performs an async TXT lookup on
_dmarc.$domainand returns the raw DMARC policy string, orundefif none exists. Applies the same parent-domain fallback logic as the original. - md_async_message_contains_virus_clamd($clamd_sock)
-
Async replacement for
message_contains_virus_clamdfrom Mail::MIMEDefang::Antivirus.Sends a
SCAN $CWD/Workcommand to the clamd daemon over a socket and interprets the response.$clamd_sockmay be a Unix socket path or ahost:portstring; defaults to$ClamdSock.Note: the
SCANcommand instructs clamd to open the path on its own filesystem. This only works when clamd runs on the same host as MIMEDefang. For remote clamd, usemd_async_message_contains_virus_clamdscaninstead.Returns the standard virus-scanner triplet
($code, $category, $action):(0, 'ok', 'ok') clean (1, 'virus', 'quarantine') virus found (999, 'cannot-execute', 'tempfail') cannot connect (999, 'swerr', 'tempfail') scan error - md_async_message_contains_virus_clamdscan($conf)
-
Async replacement for
message_contains_virus_clamdscanfrom Mail::MIMEDefang::Antivirus.Spawns
clamdscan --streamwhich uses theINSTREAMwire protocol, streaming file data to clamd rather than asking it to open a local path. This makes it suitable for both a local Unix-socket clamd and a remote TCP clamd.$confis the path toclamd.conf; defaults to$Features{'Path:CLAMDCONF'}. The socket clamd listens on (Unix or TCP) is determined by theLocalSocket/TCPAddr+TCPSocketdirectives in that config file.Returns the standard virus-scanner triplet
($code, $category, $action):(0, 'ok', 'ok') clean (1, 'virus', 'quarantine') virus found (1, 'not-installed', 'tempfail') clamdscan binary not found (999, 'cannot-execute', 'tempfail') could not spawn / timeout (999, 'swerr', 'tempfail') scan error (clamdscan exit >= 2) - md_async_spamc_check(%args)
-
Async replacement for
md_spamc_checkfrom Mail::MIMEDefang::Antispam.Sends the message to spamd using the raw SPAMC wire protocol over an async socket, without requiring Mail::SpamAssassin::Client.
Args:
host(default127.0.0.1),port(default 783),user(default current user),timeout(default 30s).Returns the same four-element list as
md_spamc_check:($score, $threshold, $report, $isspam), orundefon failure. - md_async_spam_assassin_check()
-
Drop-in replacement for
spam_assassin_checkfrom Mail::MIMEDefang::Antispam.Runs SpamAssassin in-process (no spamd required), reading
./INPUTMSG. Returns the same four-element list:($hits, $required_hits, $tests_list, $full_report), orundefwhen SpamAssassin is not installed or INPUTMSG cannot be read.For a network check against a running spamd, use
md_async_spamc_checkinstead. - md_async_rspamd_check($uri)
-
Async replacement for
rspamd_checkfrom Mail::MIMEDefang::Antispam.POSTs the message to the Rspamd HTTP API at
$uri/checkv2using a raw HTTP/1.0 request over an async TCP socket (noLWP::UserAgentrequired). Requires JSON::PP (Perl core since 5.14) for response parsing.$uridefaults tohttp://127.0.0.1:11333.Returns the same six-element list as
rspamd_check:($hits, $required_score, $tests, $report, $action, $is_spam), or(0, 0, '', '', 'soft reject', 'false')on connection failure.
SYNOPSIS
use Mail::MIMEDefang::Async;
use Mail::MIMEDefang::Async::Checks qw(...);
use Mail::MIMEDefang::Async::Results qw(...);
md_async_init(max_concurrency => 8, global_timeout => 10);
my $result = md_async_run_checks([
md_async_check_dnsbl(ip => $client_ip, zone => 'zen.spamhaus.org'),
md_async_check_rdns(ip => $client_ip),
]);
# Drop-in replacements
my $listed = md_async_relay_is_blacklisted($client_ip, 'zen.spamhaus.org');
my $dmarc = md_async_dmarc_verify($sender_domain);
my ($code, $cat, $act) = md_async_message_contains_virus();
my ($score, $thr, $rep, $spam) = md_async_spamc_check();
my ($hits, $req, $sym, $rpt, $action, $spam) = md_async_rspamd_check();
SEE ALSO
Mail::MIMEDefang::Async::Checks, Mail::MIMEDefang::Async::Results, Mail::MIMEDefang::Net, Mail::MIMEDefang::SPF