Dave Taylor
Hewlett-Packard Laboratories
1501 Page Mill Road
Palo Alto CA 94304
email: taylor@hplabs.HP.COM or hplabs!taylor
Datacomp Systems, Inc.
3837 Byron Road
Huntingdon Valley, PA 19006-2320
email: elm@dsinc.UUCP or dsinc!elm
At the same time I often get mail that, while it is interesting and important, can easily be filed to be read later, without ever actually having to cluttering up my incoming mailbox.
This, then, is what filter does! The filter program allows you to define a set of rules by which all incoming mail should be screened, and a subsequent set of actions to perform based on whether the conditions were met or not. Filter also has the ability to mail a summary of what actions it performed on the incoming mail as often as you'd like.
Individual conditions are joined together by using the word ``and'', and the logic of a condition can be flipped by using ``not'' as the first word (e.g. `not subject "joe"'). We'll see more examples of this later.
Note that the ``or'' logical conjunction isn't a valid part of the filter conditional statement.
Finally, <action> can be any of;
Foldernames can contain any of a number of macros, too, as we'll see in the example ruleset below. The macros available for the string fields are;
The file itself needs to reside in your home directory and be called .filter-rules. Here's an example:
# $HOME/.filter-rules # # Filter rules for the Elm Filter program. Don't change without some # serious thought. (remember - order counts) # # (for Dave Taylor) # rule 1 if (from contains "!uucp") then delete # rule 2 to "postmaster" ? save "/tmp/postmaster-mail.%d" # rule 3 if (to "culture" and lines > 20) ? save "/users/taylor/Mail/culture" # rule 4 subject = "filter test" ? forward "hpldat!test" # rule 5 if [ subject = "elm" ] savecopy "/users/taylor/Mail/elm-incoming" # rule 6 subject = "display-to-console" ? execute "cat - > /dev/console"
% filter -r
Rule 1: if (from = "!uucp") then
Delete
Rule 2: if (to = "postmaster") then
Save /tmp/postmaster-mail.<day-of-week>
Rule 3: if (to = "culture" and lines > 20) then
Save /users/taylor/Mail/culture
Rule 4: if (subject = "filter test") then
Forward hpldat!test
Rule 5: if (subject="elm") then
Copy and Save /users/taylor/Mail/elm-incoming
Rule 6: if (subject="display-to-console") then
Execute "cat - > /dev/console"
There are a few things to notice - first off, these are the
parsed and rebuilt rules, so we can see that they are all in a
consistent format. Also, notice on the filename for rule 2 that
the program has correctly expanded the %d macro to be the day
of the week. It is highly recommended that you always check your ruleset before actually letting the program use it!
The format for the entry in the .forward file (located in your home directory) is simply;
"| /usr/local/bin/filter"
Allright, it isn't quite that simple! Since filter will be in-
voked by processes that don't know where you are logged in, you
need to have some way to trap the error messages. For ease of
use, it was decided to have all the messages written to the file
specified by `-o' (or stderr) which means that you have two main
choices for the actual entry. Either;
"| /usr/local/bin/filter -o /dev/console"
which will log all errors on the system console (each error is
prefixed with ``filter (username)'' to distinguish it), or;
"| /usr/local/bin/filter -o /tmp/joe.filter_errors"
If you want to have a copy saved to a file. Note that the quotes are a required part of the line. A possible strategy
would be to have the errors written to a file and to then have a
few lines in your .login script like:
if ( -f .filter_errors) then
echo " "
echo "Filter program errors;"
cat /tmp/joe.filter_errors
echo " "
endif
You can also use the -v flag in combination with the above to
have a more verbose log file saved by having your .forward file;
"| /usr/local/bin/filter -vo /tmp/joe.filter_errors"
Suffice to say, you can get pretty tricky with all this!!
The difference between the two is best demonstrated by example:
% filter -s
Summary of Filter Activity
__________________________
A total of 418 messages were filtered:
The default rule of putting mail into your mailbox
applied 364 times (87%)
Rule #1: (delete message)
applied 1 time (0%)
Rule #2: (save in "/users/taylor/Filtered-Mail/netnews.12")
applied 8 times (2%)
Rule #3: (save in "/users/taylor/Filtered-Mail/postmaster.12")
applied 14 times (3%)
Rule #5: (save in "/users/taylor/Filtered-Mail/risks.12")
applied 3 times (1%)
Rule #6: (save in "/users/taylor/Filtered-Mail/rays.12")
applied 28 times (7%)
versus:
% filter -S
the output as listed above, followed by:
Explicit log of each action;
Mail from taylor about Filter Summary
PUT in mailbox: the default action
Mail from news@hplabsz.hpl.hp.com about Newsgroup comp.editors created
PUT in mailbox: the default action
Mail from root about Log file: cleanuplog
PUT in mailbox: the default action
[etc etc]
To actually use either of the summarizing options, there are two
ways that are recommended; The preferred way is to have a line in either your crontab (ask your administrator for help with this) that invokes the filter program as often as you desire with the -s flag. For example, I have a summary mailed to me every morning at 8:00 am:
0 8 * * * "/usr/local/bin/filter -s | elm -s 'Filter Summary' taylor"
An alternative is to have your .login execute the command each
time. Note that if you want to have your log files cleared out each time the summary is generated you'll need to use the -c flag too. Also, if you want to keep a long list of actions performed you can do this by saving it as you display it. A way to do this would be, if you were to have the invocation in your .login script, to use:
echo "Filter Log;"
filter -c -s | tee -a PERM.filter.log
which would append a copy of all the output to the file
PERM.filter.log and would avoid you having to read larger and
larger summaries of what the program had done.
For example, we can use the -n flag to filter, which means `don't actually do this, just tell me what rule you matched, if any, and what action you would have performed' (you can see why a single letter flag is easier to type in!!), and feed it each message in our mailbox by using a command like;
% set message=1
% set total_messages=`messages`
% while (1)
> if ($message > $total_messages) exit
> echo processing message $message
> readmsg -h $message | filter -n
> echo " "
> @ messages++
> end
which will then hand each of the messages in your mailbox to the
filter program and display what action would have been taken with
that message and why. For example, if we do this for a few interesting messages in my mailbox, we'd end up with output like:
Mail from taylor about filter test
FORWARDED to hpldat!taylor by rule;
subject="filter test" ? forward "hpldat!test"
Mail from bradley%hplkab@hplabsc about Re: AI-ED mailing address for HP
PUT in mailbox: the default action
Mail from taylor about display-to-console
EXECUTED "cat - > /dev/console"
(sharp users will notice that this is exactly the same format as
the longer summary listing)
If not, then the message is enclosed in a message of the form:
From taylor Thu Oct 2 15:07:04 1986
Date: Thu, 2 Oct 86 15:06:58 pdt
Subject: "filter test"
From: The filter of taylor@hpldat <taylor>
To: hpldat!taylor
X-Filtered-By: filter, version 1.4
-- Begin filtered message --
From taylor Thu Oct 2 15:06:41 1986
Date: Thu, 2 Oct 86 15:06:33 pdt
From: Dave Taylor <taylor>
Subject: filter test
Just a simple test.
-- End of filtered message --
The subject of the actual message is the same as the subject of
the message being forwarded, but in quotes. The `From:' field
indicates how the message was sent, and the `X-Filtered-By:'
identifies what version of filter is being used.
As I see it, the main things missing are;
Order counts in the rules. Beware!
Matching is pretty simple - make sure your patterns are sufficiently exclusive before having any destructive rules.
Finally, as with the rest of the Elm mail system, I welcome feedback and suggestion on how to improve this program!!