#!/usr/bin/perl -w # Spamassassin filter for POP3 mail accounts # Copyright (C) 2003 Nigel Horne, Wharfedale Computers Ltd. # njh@despammed.com # 21/11/02: Use DNS to check originating host exists to help stop spam # 22/11/02: Use MX DNS records. # 25/11/02: Flush items put in sendmail's queue. # 2/12/02: Handle e-mail addresses without the realname # 21/1/03: Added spam blocker # 22/1/03: Don't forward spam message. Improved spam warning messages # 24/1/03: Added virus checker. use strict; use Net::POP3; use Net::DNS; use Mail::SpamAssassin; my $hostname = 'smsltd.demon.co.uk'; my $server = 'pop3.demon.co.uk'; my $user = 'smsltd'; my $password = 'xyzzy'; my $pop3 = Net::POP3->new($server, Timeout => 60) or die "Cannot connect to $server: $!"; my $nummessages = $pop3->login($user, $password); if(!defined $nummessages) { die "Cannot login to $server: $!"; } if($nummessages == 0) { print "Nothing to do\n"; $pop3->quit(); exit 0; } print "Retrieving $nummessages messages from $server\n"; my $messages = $pop3->list() or die "Cannot get list of messages from $server: $!"; my $resolver = Net::DNS::Resolver->new; sub CATCH_PIPE { }; $SIG{'PIPE'} = "CATCH_PIPE"; MESSAGE: foreach my $msgid (keys %$messages) { print "Forwarding message $msgid ..."; my $message = $pop3->get($msgid); defined $message or die "\nCan't retrieve message $msgid: $!"; print "\n"; my $from = ""; my @messageArray = @$message; foreach (@messageArray) { if(/^From: (.+)/) { $from = $1; if(($from =~ /.*\<.+\@(.+)\>/) || ($from =~ /.+\@(.+)/)) { unless(mx($resolver, $1)) { print "Unknown host $1 in $from, message not forwarded\n"; # You may wish to comment this out $pop3->delete($msgid); next MESSAGE; } } else { $from = 'unknown'; } last; } } if(open(CLAM, "|clamscan --disable-summary -i --mbox -")) { print CLAM "From $from\n"; foreach (@messageArray) { print CLAM $_; } if(close CLAM != 0) { if(($from ne "") && open(MAIL, "|/usr/lib/sendmail \"-f$from\" -t -odq")) { print MAIL "From MAILER-DAEMON\n"; print MAIL "To: $from\n"; print MAIL "Cc: postmaster\n"; print MAIL "Subject: Virus intercepted\n\n"; print MAIL "A message sent from you contained a virus.\n"; print MAIL "It has not been forwarded to the $hostname domain.\n"; close MAIL; } print "Not forwarding message containing a virus\n"; # You may wish to comment this out $pop3->delete($msgid); next MESSAGE; } } my $ma = Mail::SpamAssassin::NoMailAudit->new(data => \@messageArray); # This often gives this error: # Use of uninitialized value in split at /usr/lib/perl5/5.8.0/File/Spec/Unix.pm line 216 my $sa = Mail::SpamAssassin->new; my $status = $sa->check($ma); if($status->is_spam()) { $status->rewrite_mail(); # Don't report if the from is forged as us, or if it's a bounce # of a bounce my $isbounce = 0; foreach (@messageArray) { if(/^From: (.+)\@$hostname(.*)/) { $isbounce = 1; last; } } $sa->report_as_spam($ma) unless $isbounce; print "Not forwarding spam message\n"; # You may wish to comment this out... $pop3->delete($msgid); $status->finish(); next MESSAGE; } $status->finish(); undef $status; undef $sa; undef $ma; # If we're here it probably isn't spam if($from eq "") { $from = 'unknown'; } elsif(open(MAIL, "|/usr/lib/sendmail \"-f$from\" -t -odq")) { print MAIL "From njh\@despammed.com\n"; print MAIL "To: $from\n"; print MAIL "From: Nigel Horne \n"; print MAIL "Subject: Please update your address book\n\n"; print MAIL "This is an automatic message that has been sent\n"; print MAIL "in response to a message sent to $hostname.\n\n"; print MAIL "The domain $hostname is about to disappear.\n"; print MAIL "Please update your address book to point to bandsman.co.uk.\n"; close MAIL; } if(open(MAIL, "|/usr/lib/sendmail \"-f$from\" -t")) { # Send TO field first foreach (@$message) { if(/^To: (.+)\@$hostname(.*)/i) { print MAIL "To: $1$2\n"; print "To: $1$2\n"; last; } elsif (/^To: (.+)/i) { print MAIL "To: $1\n"; print "To: $1\n"; last; } elsif (/^$/) { # End of headers. No To: found. Must be spam... print "Not forwarding spam message\n"; $pop3->delete($msgid); close MAIL; next MESSAGE; } } my $inhead = 1; foreach (@$message) { if($inhead) { (/^From: (.+)/) && print "From: $1\n"; (/^Subject: (.+)/) && print "Subject: $1\n"; unless (/^To: .+\@$hostname.*/) { print MAIL $_ || die "Sendmail has disappeared: $!\n"; } $inhead = 0 if(/^$/); } else { print MAIL $_ || die "Sendmail has disappeared: $!\n"; } } print MAIL "\nForwarded from the pop3 account at $server."; print MAIL "\nThis service will terminate soon. You *have* been warned.\n"; if(close MAIL) { $pop3->delete($msgid); } else { warn "e-mail may have failed\n"; # You may wish to comment this out... $pop3->delete($msgid); } } } print "Finished\n"; $pop3->quit();