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 " " endifYou 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 firstname.lastname@example.org 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.logwhich 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++ > endwhich 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!!