Roger Walker wrote:
The plugin in the current distribution has a note not to use 2.50,
but 2.40 or newer. The current version is 2.61. Does this work properly
with the supplied plugin?
There are (at least) three ways to run SpamAssassin from within qpsmtpd:
1) Call Mail::SpamAssassin directly; this is slow and eats RAM like mad, so it
is not really recommended for production servers.
2) Call spamc which talks to spamd (a resident Mail::SpamAssassin process); this
is much faster than #1 (since you don't need to spawn a large Perl process for
each e-mail).
3) Talk to spamd directly from qpsmtpd. This has the disadvantage that if the
internal spamd API changes, the plugin needs to change too. It has the
advantage that it does not require spawning any other process (even one as small
as spamc), so it should be faster than #2. It will certainly require the least
amount of RAM of any solution.
Both #'s 2 and 3 can also take advantage of the Mail::SpamAssassin 2.60+ feature
of using Unix Domain Sockets to communicate with spamd, which should also be a
distinct performance gain (as well as being much better security-wise). spamd
can also be potentially run using PPerl (Persistent Perl) which makes everything
even faster.
Personally, I am using method #3 with a patched version of the base spamassassin
plugin which enables the Domain Sockets support. I am working on a shim module,
currently called Mail::SpamAssassin::SpamC, which will encapsulate the spamd
API, so that future changes will not be required to the qpsmtpd plugin.
I've attached my current patch, which is based on earlier patches by Keith Ivey
and Peter J Holzer. I am currently using M::SA 2.60 on my machines, but I don't
know of any reason why 2.61 wouldn't work just as well.
HTH
John
# cvs diff -u plugins/spamassassin
Index: plugins/spamassassin
===
RCS /cvs/public/qpsmtpd/plugins/spamassassin,v
retrieving revision 1.5
diff -u -r1.5 spamassassin
--- plugins/spamassassin18 Mar 2003 09:53:37 - 1.5
+++ plugins/spamassassin3 Jan 2004 16:20:08 -
@@ -49,6 +49,12 @@
The default is to never munge the subject based on the SpamAssassin score.
+=item spamd_socket [/path/to/socket]
+
+Beginning with Mail::SpamAssassin 2.60, it is possible to use Unix
+domain sockets for spamd. This is faster and more secure than using
+a TCP connection.
+
=back
With both options the configuration line will look like the following
@@ -92,8 +98,17 @@
my $paddr = sockaddr_in($port, $iaddr);
my $proto = getprotobyname('tcp');
+ if ( $self-{_args}-{spamd_socket} =~ /^([\w\/.]+)$/ ) { # connect to Unix Domain
Socket
+my $spamd_socket = $1;
+
+socket(SPAMD, PF_UNIX, SOCK_STREAM, 0)
+ or $self-log(1, Could not open socket: $!) and return (DECLINED);
+
+$paddr = sockaddr_un($spamd_socket);
+ } else {
socket(SPAMD, PF_INET, SOCK_STREAM, $proto)
or $self-log(1, Could not open socket: $!) and return (DECLINED);
+ }
connect(SPAMD, $paddr)
or $self-log(1, Could not connect to spamassassin daemon: $!) and return
DECLINED;
@@ -102,9 +117,11 @@
$transaction-body_resetpos;
- print SPAMD REPORT_IFSPAM SPAMC/1.0 . CRLF;
+ print SPAMD SYMBOLS SPAMC/1.0 . CRLF;
# or CHECK or REPORT or SYMBOLS
+ print SPAMD X-Envelope-From: , $transaction-sender-format, CRLF;
+
print SPAMD join CRLF, split /\n/, $transaction-header-as_string
or warn Could not print to spamd: $!;
@@ -124,16 +141,24 @@
$transaction-header-add(X-Spam-Check-By, $self-qp-config('me'));
}
+ my ($flag, $hits, $required);
while (SPAMD) {
#warn GOT FROM SPAMD1: $_;
-next unless m/\S/;
-s/\r?\n$/\n/;
-my @h = split /: /, $_, 2;
+last unless m/\S/;
+if (m{Spam: (\w+) ; (-?\d+\.\d) / (-?\d+\.\d)}) {
+ ($flag, $hits, $required) = ($1, $2, $3);
+}
+ }
-$transaction-header-add(@h);
-last if $h[0] eq Spam and $h[1] =~ m/^False/;
+ my $tests = SPAMD || '';
+ $tests =~ s/\s+$//;
+ $self-log(5, $flag, hits=$hits, required=$required, tests=$tests) if $tests;
+ $tests =~ s/(.{1,60}(?:,|$))/$1\n\t/g; # wrap
+ $tests =~ s/\s+$//;
- }
+
+ $transaction-header-add('X-Spam-Status', $flag, hits=$hits required=$required .
+( $tests ? \n\ttests=$tests : '' ) );
return (DECLINED);
}
@@ -157,7 +182,9 @@
return DECLINED unless $score = $self-{_args}-{munge_subject_threshold};
my $subject = $transaction-header-get('Subject') || '';
- $transaction-header-replace('Subject', ***SPAM*** $subject);
+ $subject = sprintf('@SPAM(%05.2f) %s', $score, $subject);
+ $self-log(5, qq(munging subject to $subject));
+ $transaction-header-replace('Subject', $subject);
return DECLINED;
}