filtering incoming mail? :-|

Rich Kaul kaul at icarus.eng.ohio-state.edu
Tue Dec 18 05:46:31 AEST 1990


In article <SHAWN.90Dec17133759 at litsun8.litsun.epfl.edu> shawn at litsun8.litsun.epfl.edu (Shawn Koppenhoefer) writes:
   Is it possible to somehow filter mail
   so that any mail with a keyword in
   the subject line is junked right away?
   [...]
   I've aked a number of people and they
   all tell me it's impossible.

It's possible.  You might look at elm's filter function, but I'll show
you how to do it yourself on BSD systems.  For SysV sites you can do a
similar procedure, but it has to act directly on your mail file.

Under BSD you can create a ~/.forward file which can run a filter on
your mail.  For example, my ~/.forward file looks like:
"|/usr/1/kaul/bin/ppmd /usr/1/kaul kaul >>/usr/1/kaul/.maillog 2>&1"
I'll append the version of the perl script I use to filter my mail at
the end of this.  It looks at the 'From ' and 'CC: ' lines to figure
out who's sending me the mail to catagorize it.  You can easily change
it to work on the Subject: line if you like.  I have a shell version
but that uses about 4 times the computer resources.  I'll send it to
you if you like.

A brief overview: I get too much mail, so I filter it.  A small list
of people can send me stuff that actually gets into my mail box for my
immediate attention.  Nearly everything else is placed into a
structure where I can run my news reader (GNUS, an emacs based news
reader) on the individual messages in exactly the same manner as
reading newsgroups.  These are the lower priority, read once and throw
away messages, or stuff from mailing lists that I don't want to
constantly have interrupting me.  I only see those when I find time to
read news.  There are a few other support things that are needed to
turn this into a complete news reading system, but those are on
tut.cis.ohio-state.edu in ~ftp/pub/gnu/gnus if you want to see them.

#!/usr/bin/perl

# A crude attempt at a perl mail delivery agent.  The basic premise is
# that mail from certain people demands attention immediately, so it
# gets put in the normal system mailbox.  Mail from mailing lists is
# to be placed in various subdirectories in a format that GNUS can
# handle for reading.  Mail from the random users gets placed in a
# third directory ($root).  This is, of course, easily customizable.
# Delivering into a directory requires a .last file to keep track of
# article numbers for GNUS.
#
# Pardon the perl style; I'm just learning but this works!  Comments
# welcome.
#
# Author:	Rich Kaul (kaul at icarus.eng.ohio-state.edu)
# Date:		11/13/90
# The credit where credit is due department:  the core of the message
# parsing is based on Larry Wall's mailagent script, although the rest
# of this ugly mess (which nobody else would want to claim) is mine.

($HOME, $USER) = @ARGV;

$root = "$HOME/Memos/personal";		# root of personal news tree.
$dest = $root;
$box = "/usr/spool/mail/$USER";		# default mail box.
$GIVE_UP_BOX = "$HOME/mail_dump";	# emergency dumping box.

$LOCK_SH = 1;				# Values for flock() calls.
$LOCK_EX = 2;
$LOCK_NB = 4;
$LOCK_UN = 8;

umask(077);				# Get a little privacy.

# Now run and get the headers.  We have to parse the headers before we
# can figure out delivery.
while (<stdin>) {
    # Do this on the From_ line only.
    if (1 .. 1) {
	if (/^From\s+(\S+)\s+[^\n]*(\w{3}\s+\d+\s+\d+:\d+)/) { $from = $1; }
	$from =~ s/@.*//;		# remove trailing @machine
	$from =~ s/%.*//;		# remove trailing %machine
	$from = $1 if $from =~ /.*!([^\n]+)/; # remove leading ! paths
    }

    # This section operates on the header of the message.  We create
    # an array of header keys to work on later.
    if (1 .. /^\s*$/) {
	s/^From: ([^<]*)\s+<(.*)>$/From: $2 ($1)/;	# rewrite ugly header
	$header .= $_;
	chop;
	if (/^\s*$/) {
	    foreach $key (keys(header)) {
		eval "\$H$key = \$header{'$key'}";
	    }
	}
	else {
	    if (s/^([-\w]+):\s*//) {
		($headline = $1) =~ y/A-Z-/a-z_/;
		$header{$headline} .= "\n" if $header{$headline} ne '';
	    }
	    else {
		s/^\s+/ /;
	    }
	    $header{$headline} .= $_;
	}
    }
    # And here we make the body of the message.
    else {
	$body .= $_;
	}
}

# Ok, now figure out where to deliver the message.  The first case is
# mail from well behaved mailing lists (i.e. ones that advertise that
# they are mailing lists).
if($from =~ /firearms/) {$dest = "$root/firearms";}
elsif($from =~ /Info-VM/ || $from =~ /Bug-VM/) {$dest="$root/bug-vm";}
elsif($from =~ /freemacs/) {$dest = "$root/freemacs";}

# Sometimes we have dumb mailing lists that can't get their act
# together.  The interviews, oct and some freemacs stuff are prime examples.
if ($Hto =~ /gif/ || $Hcc =~ /gif/) {$dest = "$root/gif";}
elsif($Hto =~ /gnuplot/ || $Hcc =~ /gnuplot/) {$dest = "$root/gnuplot";}
elsif ($Hto =~ /freemacs/ || $Hcc =~ /freemacs/) {$dest = "$root/freemacs";}
elsif ($Hto =~ /interviews/i || $Hcc =~ /interviews/i ) { 
    $dest = "$root/interviews";}
elsif ($Hto =~ /vem/i || $Hto =~ /oct/i || $Hcc =~ /vem/i || $Hcc =~ /oct/i) {
    $dest = "$root/vem";}
elsif($Hto =~ /xviewbug-trackers/ || $Hcc =~ /xviewbug-trackers/) {
    $dest = "$root/xview";}

# Here we dump system messages.
if($from =~ /root/ || $from =~ /news/) { $dest = "$root/system";}

# Now we list the people who can crash into the mailbox.
if($from =~ /karl_kl/ || $from =~ /alden/ || $from =~ /monty/) {$dest = $box;}
elsif($from=~/pnelson/ || $from=~/wilson/i || $from =~ /gratz/i) {$dest=$box;}
elsif($from =~ /bibyk/ || $from =~ /adkins/ || $from =~ /zaka/) {$dest = $box;}
elsif($from =~ /kaul/ || $from =~ /aspark/) {$dest = $box;}

# Now we do the delivery.  There are two cases.  If we are delivering
# to a directory find and update the .last file there.
if ( -d $dest ) {
    # It's going to be a news article, so change the From_ line
    $header =~ s/^From /Unix-From: /;
    $all = $header . $body;

    $count_file = "$dest/\.last";
    open(COUNTER,"+<$count_file")|| do gag("Can't open $dest/.last ($< $>): $!");
    while (<COUNTER>) {
	chop;
	$count = $_;
	$count++;
    }
    do flocker(COUNTER,$LOCK_EX);	# Lock the file, just in case.
    seek(COUNTER,0,0);
    print COUNTER $count,"\n";
    do flocker(COUNTER,$LOCK_UN);

    # We now have the article number we need.
    open(ART,">>$dest/$count") || do gag("Can't open $dest/$count ($< $>): $!");
    print ART $all,"\n";
} else {
    # Here we're delivering to a file, which is easier.  Build and deliver.
    $all = $header . $body;
    open(BOX, ">>$dest") || do gag ("Can't open $dest ($< $>): $!");

    do flocker(BOX,$LOCK_EX);
    print BOX $all,"\n\n";
    do flocker(BOX,$LOCK_UN);
}

# File locking subroutine.
sub flocker {
    local ($file, $mode) = @_;
    eval 'flock($file,$mode);';
    seek($file, 0, 2);		# in case it was appended while we were waiting
}

# For some reason mail couldn't get delivered.  Dump the message in the
# emergency mailbox and exit.
sub gag {
    open(ERR_BOX, ">>$GIVE_UP_BOX") || die "I'm really hosed.  I can't even open the emergency box $GIVE_UP_BOX\n";

    print @_;
    do flocker(ERR_BOX,$LOCK_EX);
    print ERR_BOX $all,"\n\n";
    do flocker(ERR_BOX,$LOCK_UN);
    exit 1;
}
    

-- 
Rich Kaul                         | Every man is given the key to the door
kaul at icarus.eng.ohio-state.edu    | of heaven; unfortunately, the same key
or ...!osu-cis!kaul		  | opens the door to hell.



More information about the Comp.unix.questions mailing list