#!/usr/local/bin/perl -w use strict; use Mail::Audit; use Mail::Audit::Razor; my @pw = getpwuid($<); my $name = $pw[0]; my $home = $pw[7]; open STDERR,">> $home/.mailfiltererr"; my @acceptfrom; my @acceptsubj; my %autofile; my @spamsubjects; my @spamsenders; my $folders = "$home/"; my @alias = ( $name ); my $fh = new IO::File; if ($fh->open("$home/.mailfilterrc")) { while (my $line = $fh->getline) { chomp $line; $line =~ s/^\s+//; $line =~ s/\s+$//; next unless $line; my ($key,$val) = $line =~ /^\s*(\w+)\s*=\s*(.*)$/; next unless $key && $val; if ($key eq "fromok") { push @acceptfrom,$val; } elsif ($key eq "subjectok") { push @acceptsubj,$val; } elsif ($key eq "autofile") { my ($k, $v) = $val =~ /^\s*(\w+)\s*->\s*(.*)$/; $autofile{$k} = $v if $k && $v; } elsif ($key eq "spamsubjects") { push @spamsubjects,$val; } elsif ($key eq "spamsenders") { push @spamsenders,$val; } elsif ($key eq "folders") { $folders = "$val/"; } elsif ($key eq "alias") { push @alias,$val; } else { print STDERR "Error on config file line $.: $key\n"; } } $fh->close; } my $msg = Mail::Audit->new; my $from = $msg->from || ""; my $to = $msg->to || ""; my $cc = $msg->cc || ""; my $subj = $msg->subject || ""; chomp ($from, $to, $cc, $subj); sub logit { my $disp = shift; open LOG,">>$home/.mailfilterlog"; my $logmsg = "$disp:$to:$cc:$from:$subj"; $logmsg =~ s/[\r\n]/ /g; print LOG "$logmsg\n"; close LOG; } foreach my $k (@acceptfrom) { if ($from =~ /$k/i || $to =~ /$k/ixm || $cc =~ /$k/ixm) { logit("from"); $msg->accept; } } foreach my $k (@acceptsubj) { if ($subj =~ /$k/i) { logit("subj"); $msg->accept; } } foreach my $k (keys %autofile) { if ($from =~ /$k/i) { logit("auto"); $msg->accept("$folders/$autofile{$k}"); } } if ($msg->is_spam) { logit("razor"); $subj = "[razor] $subj"; $msg->replace_header("Subject", $subj); $msg->accept("$folders/spam"); } foreach my $k (@spamsenders) { if ($from =~ /$k/i) { logit("spamsender"); $msg->accept("$folders/spam"); } } foreach my $k (@spamsubjects) { if ($subj =~ /$k/i) { logit("spamsubject"); $msg->accept("$folders/spam"); } } foreach my $k (@alias) { if ($to =~ /$k/ixm || $cc =~ /$k/ixm) { logit("ok"); $msg->accept; } } logit("nottome"); $msg->accept("$folders/spam"); __END__ =head1 mailfilter Filters mail using Mail::Audit and Vipul's Razor. Each message is logged to F<.mailfilterlog> in the user's home directory. The log contains a name and the To, Cc, From and Subject headers from the message separated by colons. mailfilter processes the message as follows. Each step is labeled with its log file entry name. =over 4 =item from If the sender name matches a fromok regular expression, the message is accepted to the user's inbox. =item subj If the subject matches an subjectok regular expression, the message is accepted to the user's inbox. =item auto If the sender name matches an autofile entry's regular expression, the message is accepted to the mailbox specified in the autofile entry. =item razor If Vipul's Razor thinks the message is spam, C<[razor]> is prepended to the message's subject and the message is accepted to the spam folder. The subject is changed to give a visual indication that the message was found by Razor. Users may wish to run C on messages in their spam folder that were not detected by Razor. =item spamsender If the sender name matches a spamsender regular expression, the message is accepted to the spam folder. =item spamsubject If the subject matches a spamsubject regular expression, the message is accepted to the spam folder. =item ok If the account name or an alias is included in the To: or Cc: headers, the message is accepted. Since much spam is addressed to a large list of users in Bcc headers, this step will catch a lot of spam. =item nottome The message is accepted to the spam folder. =back =head2 Configuration mailfilter can be configured by editing $HOME/.mailfilterrc. The following configuration options may be specified. =over 4 =item alias = EnameE Enters I as a valid alias for the account. Mail not addressed to the account name or a listed alias may be considered spam. =item folder = EpathE Specifies the name of the directory where the user's mail files are stored. =item fromok = EregexE Adds a regular expression to the list of senders that mail will be accepted from. =item subjectok = EregexE Adds a regular expression to the list of subjects that will be accepted. =item autofile = Esender-regexE -> EfolderE Adds an autofile entry. If the from field matches the regular expression, the message will be saved to the specified folder. =item spamsubjects = EregexE Adds a regular expression to the list of subjects that will be accepted as spam. =item spamsenders = EregexE Adds a regular expression to the list of senders that send spam. =back =head2 Sample .mailfilterrc alias = tom folders = /home/pfau/mail fromok = vmsperl fromok = lunics fromok = razor subjectok = lunics autofile = breakpoint -> Newsletters/New spamsubjects = \s+\d+$ spamsubjects = \s{7,}\w+$ The C line specifies I as a valid alias for my account. Mail address to pfau (my username) or tom will be accepted. My mail folders are in a directory called I in my home directory. Mail coming from a sender address including the strings I, I, or I will be accepted as will be messages with I in the subject line. Mail coming from a sender address including the string I will be stored into the New folder in the Newsletters directory in my folder directory. Any mail with a subject that ends with some whitespace and a string of digits will be considered spam as will messages with a subject that ends with a string of at least seven whitespace characters followed by a string of alphanumerics. =head2 Comments Looking at my current .mailfilterlog reveals the following. =over 4 =item Matching a fromok: 814 (55%) I have a rather large list of names here which includes mailing lists and a bunch of people who like to send out jokes and things to large distribution lists using Bcc headers. =item Matching a subjectok: 1 I only have one entry here for a fairly quiet mailing list. =item Matching an autofile: 18 Some newsletters I get on a regular basis get autofiled for reading when I find the time. =item Spams caught by Razor: 353 (24%) Not a single false positive as far as I can recall. =item Matching a spamsender: 3 I have a couple of entries here for places that send me messages at irregular intervals. I am sure I never subscribed so I don't think I should have to unsubscribe. I just send them to the spam folder and submit them to razor. =item Matching a spamsubject: 12 This means they matched one of the two rules listed in the examples. =item Addressed to me: 173 (12%) Somehow got here without trigger one of the prior checks. My mail address was listed in a To or Cc so it was accepted. Of these, maybe 30 were spam. =item Messages not addressed to me: 103 (7%) Wasn't addressed to me. 83 of these were spam. The bulk of the rest were friends using Bcc and a big distribution list. As I catch them here, I add them to fromok's. =back In summary, 1477 mails; 1006 ended up in my inbox, about 30 were spam; 471 ended up in my spam folder, about 20 were not spam. Your mileage may vary... =head2 Author mailfilter was written by Thomas Pfau http://www.nbpfaus.net/~pfau/. =head2 Copyright Copyright (C) 2002 Thomas Pfau. All rights reserved. This module is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this progam; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut