1 Date: Mon, 1 Jun 1992 20:00:07 GMT
2 Subject: Mail auditing + more package
3 From: Martin Streicher <strike@convex.COM>
5 I am changing jobs, so this will be the final release of my audit
6 package until I get a new UNIX account established. There are
7 several little bugs fixed in this release that should fix
8 lots of parsing problems - other than that, this package seems very solid
9 and I have gotten good feedback on the usefulness of the package.
16 What this package does:
17 =======================
18 This package provides routines that parse an incoming mail message, divide
19 it into a header and the body of the message and further decompose
20 the mail header into its fields. The routines set variables that you
21 can query and parse in your own PERL script to determine what to do with
22 the incoming mail message.
24 To use the package, insert the following two PERL instructions to the very
25 TOP of your PERL script:
27 require '/gmaster/home/strike/work/perl/deliver/audit.pl' ||
28 die "deliver: cannot include audit.pl: $@";
33 Variables that &initialize() sets:
34 ---------------------------------
35 The routine &initialize() reads the incoming mail message and sets
36 the following variables:
38 $sender This is the sender shown on the "From " line.
40 %headers An associative array containing the lines in the mail
41 header. $header{'Subject'} contains the Subject: line;
42 $header{'Date'} contains Date:, etc.
44 If the To: or Cc: line appeared more than once in the header,
45 those lines are concatenated together into a single
46 comma-separated list of names. Other header lines that
47 appear twice are clobbered.
49 There are also many variables and arrays set for your convenience if you
50 dont want to parse the entries of %headers yourself.
52 $subject The Subject: line.
54 $precedence The Precedence: line.
56 $friendly The friendly (human) name of the sender
57 (e.g., Martin Streicher)
59 $address The email address of the sender
60 (e.g., strike@pixel.convex.com)
62 $from The login name of the sender with all addressing stripped. For
63 example, if $address was strike@pixel.convex.com, $from
66 $organization The name of the sender's organization. This is derived from
67 $address; for example strike@pixel.convex.com yields convex;
68 wizard!jim@uunet.uu.net yields wizard; jane@mach.site.co.uk
71 @to The list of names on the To: line(s). Note that the
72 name listed on the Apparently-To: line also appears in @to.
74 @cc The list of names on the Cc: line(s).
76 @received The list of received headers in the mail message that
77 show the path the message traveled to be delivered.
80 Routines that audit.pl provides:
81 --------------------------------
82 The package offers some canned routines for handling the incoming
85 &deliver() Deliver the incoming mail message. &deliver() appends
86 the incoming mail message to the end of your UNIX mail
87 drop /usr/spool/mail/<user>, where <user> is the name
88 specified in the .forward file.
90 &vacation() Reply automatically to the sender if you have a vacation
91 message in $HOME/.vacation.msg. If you do not have this
92 file, this routine does absolutely nothing. If you have
93 a .vacation.msg file, &vacation sends the sender of the
94 message an automatic reply containing that file.
96 This routine also records who you sent
97 vacation mail to; it will not send duplicate vacation messages
98 to the same person. If you change your vacation message, the
99 list is zeroed. The list of people you sent vacation mail to
100 is kept in $HOME/.vacation.log.
102 Some notes about &vacation():
103 - It will send you vacation mail. This is useful
104 to test your vacation message out.
106 - It will not send vacation mail to anyone named
107 root, mailer-daemon, postmaster, daemon or mailer.
108 This are not considered to be real users.
110 - It will not respond to mail that is labelled
111 with precendence bulk or junk.
115 This routine files the incoming mail message
116 in a hierarchy of mail folders. The top-level of the
117 hierarchy is specified in $dir; by default (if no
118 directory is specified) it is $HOME/log. The next level
119 of the hierachy is sorted by $organization; below this level
120 mail is sorted by the sender's login name.
122 For example, say you receive a message from
123 strike@pixel.convex.com; if you call &file_from(),
124 the corresponsing mail message will be filed into a mail
125 folder called $HOME/log/convex/strike. All mail sent to you
126 by strike@pixel.convex.com would be filed in this mail folder.
128 You can &file_from to file all correspondence for future
132 You can also use your own commands (scripts/programs)
133 to process an incoming mail message. &openpipe($command)
134 opens a PERL pipe to $command and pipes the mail message
137 You can use none, one or all of these routines. You can also repeat
138 and combine all of these functions to do more than one thing with a piece of
139 incoming mail (you probably only want to &deliver() the message once though).
141 For example, say you get a message from strike@pixel.convex.com. You want
142 to file the message away for auditing purposes, save the mail message in your
143 mail drop and send some vacation mail if you are gone. Use the &file_from(),
144 &deliver() and &vacation() functions to do all of these things to one message.
146 WARNING: IF YOU EXIT FROM THE PERL SCRIPT WITHOUT DOING SOMETHING
147 WITH THE MAIL MESSAGE, IT IS LOST FOREVER.
149 Actually, exiting the PERL script can be an effective way of dropping
150 unwanted mail messages. See the example below.
153 Other convenience functions for MH users:
154 -----------------------------------------
155 If you use MH, other convenience routines are provided to
156 pipe the incoming mail message to rcvstore, rcvdist and/or rcvtty.
157 There is also a special refile routine to file incoming mail messages
158 in folders according to the sender's organization and login.
160 To access the MH functions, add the following line to the TOP of your script:
162 require '/gmaster/home/strike/work/perl/deliver/mh.pl' ||
163 die "deliver: cannot include mh.pl: $@";
165 This file provides the following functions:
168 Pipe the incoming mail message to rcvstore; the $folder
169 argument is the name of the folder to store the message
172 &rcvtty() Pipe the incoming mail message to rcvtty. rcvtty
173 is MH's equivalent to biff and its output can be tailored
174 exactly like you can customize scan or inc.
177 Pipe the incoming mail message to rcvdist. $names
178 is a blank separated list of names to send the
179 message to. You can use the &ali() command (see below)
180 to expand MH aliases.
182 &ali($alias) Expand the MH alias name in $alias to the list
183 of addresses it stands for. Unlink all the other routines,
184 this routine returns an array of names, where
185 each element is an addressee on the alias.
189 File a copy of the incoming mail message into a hierarchy of
190 MH folders. The top-level directory is "log" by default unless
191 you specify another folder (all this below you Mailpath folder,
192 of course). The next level is sorted by organization name
193 and the level below that is sorted by sender's login name.
197 Writing a PERL mail auditing script:
198 ====================================
199 The best way to show what all this can do is with a specific example. Here
200 is my script (with comments!):
202 ------ script starts here -------
203 #! /usr/local/bin/perl
205 require '/gmaster/home/strike/work/perl/deliver/audit.pl' ||
206 die "deliver: cannot include audit.pl: $@";
208 require '/gmaster/home/strike/work/perl/deliver/mh.pl' ||
209 die "deliver: cannot include mh.pl: $@";
215 # My mail processing starts here
218 # If this message came from the MAILER, deliver it to me directly
219 # and do nothing else.
221 ($from =~ /MAILER/) && do { &deliver(); exit; };
223 # If this message is sent to xpixel (either To or Cc, deliver
224 # the messsage to me and exit.
226 (grep(/^xpixel/, @to, @cc)) && do { &deliver(); exit; };
228 # If the message is from a place called "lupine", this
231 $organization = "ncd" if ($organization eq "lupine");
233 # If the sender's name is in the password file, the organization
236 $organization = "convex" if ($logname = (getpwnam($from))[0]);
238 # If I am specifically named on the To or Cc line, do the default.
239 # The routine &default is below: it delivers the message, refiles
240 # it in an MH folder, sends vacation mail if I am gone, and
241 # biffs me if I am logged in somewhere.
243 (grep(/^strike/, @to, @cc)) && do {
248 # If the mail message went to x<hostname> where hostname
249 # is in our /etc/hosts, trash the message (JUST EXIT TO DROP
252 exit if (grep((/^x(.*)/ && (@n = gethostbyname($1))), @to, @cc));
254 # Throw away anything to anyone or any alias named avs-updates
256 exit if (grep(($_ eq "avs-updates"), @to));
258 # Throw away junk mail from AVS, Inc.
260 if ($organization eq "avs") {
261 exit if ($subject =~ /^(Opened|Assigned) to/);
262 exit if ($subject =~ /^(Edited|Fixed|Killed) by/);
266 # If the mail message went to an X Consortium alias,
267 # deliver it to me if it is advisory board mail. Otherwise,
268 # refile it into an archive and redistribute it to anyone at CONVEX
269 # that subscribes to it through me.
273 '/^advisory/', '/^blend/', '/^bug-trackers/',
274 '/^color/', '/^fix-trackers/', '/^fontwork/',
275 '/^imagework/', '/^xlib/', '/intrinsics/',
276 '/^mltalk/', '/^pex-si/', '/^pex-spec/',
277 '/^protocol/', '/^security/', '/^shape/',
278 '/^trackers/', '/^transport/', '/^wmtalk/',
279 '/^xbuffer/', '/^xc/', '/^xinput/',
280 '/^xtest/', '/^consortium/', '/^serialwork/',
281 '/^xie_/', '/^mtserver/'
284 foreach $list (@consortium) {
285 for (grep(eval $list, @to, @cc)) {
286 &deliver() if ($_ =~ "^advisory");
288 &rcvstore("XConsortium/$_");
289 @dist = &ali("XConsortium-$_");
290 &rcvdist(join(' ', @dist)) if ((@dist));
296 # this mail was not sent to me directly, so dont answer with vacation mail,
308 # defaults specifies what to do when I want to accept a piece
309 # of mail. It is a convenience.
318 ------ script ends ----------
323 If you want to test your PERL script, put the following in your .forward file:
325 <login>, "| <homedir>/<script> <login>
327 where <login> is your UNIX login, <homedir> is the absolute path name
328 to your home directory and <script> is the name of your PERL mail
329 auditing script. If you put this in .forward, incoming mail messages
330 will be directly sent to your mail drop AND will be piped through your
331 PERL script. You may get duplicates of some mail, but this is the best
332 way to see what your script is doing.
334 Once you are satisifed that your script works, simply replace your
337 "| <homedir>/<script> <login>
339 Please note that if your script has syntax errors, the mailer will
340 not drop your incoming mail; instead it will send you a the incoming
341 mail message and a note indicating that an unknown mailer error occurred.
343 Another way to test your script:
344 --------------------------------
345 You can also test your script by piping a UNIX mail folder (like your
346 mail drop) directly into your script. For example, say you are having
347 problems with mail from a certain sender or network alias; to debug your
348 script, copy your incoming mail box in /usr/spool/mail to a local file
349 and then pipe it to your script ala:
351 cat mail | perl -d ~/.audit
353 You can then step through the script and see how the mail message
354 is being parsed. You can add breakpoints, print statements, etc. and see
355 the script operate on the mail. If you use &vacation() or &file_from(),
356 you can watch those routines operate as well. The mail message is processed
357 as if it came directly to your script courtesy of the delivery system.