-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME
387 lines (293 loc) · 13.6 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
NAME
gurgitate-mail - an easy-to-use mail filter
SYNOPSIS
gurgitate-mail [-s SENDER] [-f RULESFILE] [-h]
DESCRIPTION
"gurgitate-mail" is a program which reads your mail and filters it
according to the .gurgitate-rules.rb file in your home directory. The
configuration file uses Ruby syntax and is thus quite flexible.
It's generally invoked either through your .forward file:
"|/path/to/gurgitate-mail"
Or through your .procmailrc file:
:0:
| /path/to/gurgitate-mail
Alternatively, if you're the sysadmin at your site, or your sysadmin is
friendly, you can use gurgitate-mail as a local delivery agent. For
postfix, put
mailbox_command=/opt/bin/gurgitate-mail
in /etc/postfix/main.cf. If you use any other MTA, and configure
gurgitate-mail as a local delivery agent, please tell me how! I want to
include this in the documentation.
COMMAND LINE OPTIONS
gurgitate-mail lets you alter its default behaviour with some
command-line flags:
-s SENDER
Sets the envelope sender to SENDER.
-f RULESFILE
Uses RULESFILE as the source for gurgitate-rules rather than the
default /$HOME/.gurgitate-rules.
-h Outputs a quick summary of the options available.
CONFIGURATION FILES
There are three configuration files used by gurgitate-mail: two are
system-wide, and the third, is the user rules file.
The two system-wide configuration files are /etc/gurgitate-rules and
/etc/gurgitate-rules-default. These are processed before and after the
user rules, respectively.
/etc/gurgitate-rules is used to handle system-wide filtering needs:
setting the default mailbox style to Maildir rather than the default
MBox, setting the spool directory, things like that.
The user configuration file is $HOME/.gurgitate-rules (or,
alternatively, $HOME/.gurgitate-rules.rb. Either work). You put your own
rules here. If the user configuration file doesn't encounter a "return"
during processing, then the additional rules contained in
/etc/gurgitate-rules-default are run. If that also doesn't return, then
mail messages are saved into the default mail spool location.
If the "-f" option is used on the commandline, then the file specified
will be used and the default rules will not. The "-f" option can be used
more than once:
gurgitate-mail -f test-rules -f additional-rules
CONFIGURATION PARAMETERS
There are several parameters that you can set to change the way that
gurgitate-mail behaves. You set a config parameter by saying, for
instance:
sendmail "/usr/sbin/sendmail"
which sets the "sendmail" parameter to "/usr/sbin/sendmail".
maildir
The directory you want to put mail folders into. This defaults to
$HOME/Mail.
logfile
Where you went gurgitate-mail's log messages to go to. The standard
location for this is $HOME/.gurgitate.log
sendmail
The full path to the sendmail program, used to deliver mail. This
can be any program that takes as its parameters the list of
addresses to deliver mail to, and that takes a mail message on
standard input.
homedir
The full path of your home directory. This defaults to whatever
your actual home directory is.
spooldir
The path where the system's mail spools goes to. This defaults to
"/var/spool/mail". On a Maildir system, this should be set to the
same as "homedir".
spoolfile
The mail spool file component of the full path of your mail spool.
This is generally your username. Maildir users should set this to
"Maildir".
folderstyle
The style of folders you prefer. This can be (at the moment) either
MBox or Maildir.
FILTER RULES
The filter rules are a series of Ruby statements, with the following
methods and variables available:
Variables
from This contains the envelope "from" address of the email message.
(Note that this isn't necessarily the same as the contents of the
"From:" header)
headers
This is an object containing the headers of the message. There are
several methods that come with this object:
body This contains the body of the email message. As of yet, there's
nothing really interesting which you can do with this, apart from
assigning to it; you can rewrite the body of an email message this
way. Dealing with attachments is planned for a future release of
"gurgitate-mail".
maildir
The directory which contains the folders, used by the "save" method
when you specify a folder as "=folder" (like Elm). Defaults to
"$HOME/Mail".
homedir
Your home directory. Read-only.
logfile
The location of the "gurgitate-mail" logfile. If set to "nil", then
no logging is done. Defaults to "$HOME/.gurgitate.log".
sendmail
The location of the "sendmail" program. Used by the "forward"
method. Defaults to "/usr/lib/sendmail".
spoolfile
The location of the mail spool. Read-only.
Methods
matches(name(s),regex)
Returns "true" if the header "name" matches the regular expression
"regex". If "name" is an array of header names, then it returns
true if at least one of the headers matches. Useful for testing
whether both "To:" and "Cc:" headers match.
from Returns the envelope "from" address of the email message. Note that
this is the same as the bare "from".
to Returns a HeaderBag (a kind of array) with the contents of the "To"
and the "Cc" headers.
to_s As per Ruby convention, returns all the headers as a "String"
object.
save(mailbox)
This saves the message to a mailbox. You can specify the mailbox as
a word with an = sign in front of it, in which case it puts it into
"maildir". If you don't use the =name format, then you need to
specify an absolute pathname. If it can't write the message to the
file you request it to, it'll attempt to write it to "spoolfile".
forward(address)
This forwards the email message to another email address.
pipe(program)
This pipes the message through "program". "pipe" returns the exit
code of the program that the message was piped through.
filter(program)
This pipes the message through "program" and returns a new
Gurgitate object containing the filtered mail. (This is handy for
external filters which modify email like, for example,
SpamAssassin, which adds a spam-score header.)
You can also say
filter(program) do
# code here
end
and it yields the newly-created Gurgitate object to the block.
headers
This returns the headers as an object of their own. This object has
its own methods:
headers[*headernames]
This returns a HeaderBag (a subclass of array) containing the
headers you asked for. You can then use the =~ operator on
this result to match the RHS regex with everything in the
HeaderBag.
You can change a header's value with "headers[name]=newvalue".
headers.match(name,regex)
Matches the header with the name "name" against the regex.
This is the same as headers[name] =~ /regex/.
headers.matches(names,regex)
Matches the headers with the names "names" against the regex.
This is the same as headers[*names] =~ /regex/.
headers.from
Returns the envelope from. You can change this with
"headers.from=newaddress" too.
return
This tells "gurgitate-mail" to stop processing the email message.
If you don't use "return", then "gurgitate-mail" will continue
processing the same mail again with the next rule. If there isn't a
"return" at the end of gurgitate-rules.rb, then "gurgitate-mail"
will save the email message in the normal mail spool.
log(message)
This writes a log message to the log file.
SIMPLE EXAMPLES
Here are some examples of "gurgitate-mail" rules, with explanations:
if from =~ /ebay.com/ then save("=ebay"); return; end
Any email from eBay (automatic end-of-auction notifications, for
example, and outbid notices) gets filed into the "ebay" folder.
if from =~ /root@/ then save("=root"); return; end
Any email from root (at any host) gets filed into a special folder.
Useful for sysadmins monitoring crontab email.
if headers.matches(["To","Cc"],"webmaster@") then
save("=webmaster")
return
end
Any email with a To: or Cc: line of "sysadmin" is saved to a "sysadmin"
folder. Useful for people with multiple role accounts redirected to
their address.
if headers["Subject"] =~ /\[SPAM\]/ then
save("=spam")
return
end
This is a different syntax for matching patterns against headers. You
can also match multiple headers in the square brackets.
if headers["Subject","Keywords"] =~ /a bad word/ then
save("=swearing")
return
end
Searches for "a bad word" in the Subject and Keywords headers, and if
it's there, saves the email in the "swearing" folder.
if headers.matches(["To","Cc"],"[email protected]") then
pipe("rcvstore +mailing-list")
return
end
Any email to a mailing list is piped through "rcvstore" to store it into
an MH folder.
That
headers.matches(["To","Cc"],/regex/)
idiom happens often enough that there's a shorthand for it:
if to =~ /[email protected]/ then
pipe("rcvstore +mailing-list")
return
end
Pipes the mail to the mailing list through "rcvstore".
ADVANCED EXAMPLES
Here are some slightly more clever examples to give you an idea of what
you can do with "gurgitate-mail". Let's suppose you have an email
whitelist in a file called $HOME/.friends, so you can determine whether
some email is likely to be spam or not.
Then if someone on your whitelist sends you email, then you
automatically save that into the "inbox" folder:
friends=homedir+"/.friends"
if FileTest.exists?(friends) and FileTest.readable?(friends) then
File.new(friends).each do |friend|
if from =~ friend.chomp then
log "Mail from friend "+friend.chomp
save("=inbox")
return
end
end
end
Okay, if someone sends you email, and it's addressed specifically to you
(and gurgitate-mail hasn't caught it in another form already), then it
might or might not be spam: put it into a "grey" folder:
my_addresses= [ /me@example\.com/i,
/me@example\.org/i,
/me@example\.net/i]; # I have three email addresses
my_addresses.each do |addr|
if headers.matches(["To","Cc"],addr) then
save("=possibly-not-spam")
return
end
end
And after that, if it's not from someone you know, and it's not
addressed to your email address either, then it's probably save to
assume that it's spam:
save("=spam")
return
This can be improved by using a Bayesian filter, though; for example,
Eric Raymond's bogofilter program (http://bogofilter.sourceforge.net)
can be automatically trained and used with the help of the
white/grey/black distinctions. Taking the example above, I'll adjust it
by adding in calls to bogofilter:
friends=homedir+"/.friends"
if FileTest.exists?(friends) and FileTest.readable?(friends) then
File.new(friends).each do |friend|
if from =~ friend.chomp then
log "Mail from friend "+friend.chomp
pipe("bogofilter -h") # <-- LINE ADDED HERE
save("=inbox")
return
end
end
end
"bogofilter -h" trains bogofilter that mail from whitelisted-people is
not to be considered spam. Okay, at the end of the .gurgitate-rules,
change
save("=spam")
return
to
save("=spam")
pipe("bogofilter -s")
return
This trains "bogofilter" that anything which doesn't pass the rest of
the filter should be considered spam. Now for the interesting bit:
Change the bit between these to use "bogofilter" to decide whether email
is to be considered spam or not:
my_addresses= [ /me@example\.com/i,
/me@example\.org/i,
/me@example\.net/i]; # I have three email addresses
my_addresses.each do |addr|
if headers.matches(["To","Cc"],addr) then
if pipe("bogofilter")==1
then
log("bogofilter suspects it might not be spam")
save("=possibly-not-spam")
else
log("bogofilter thinks it's probably spam")
save("=spam")
end
return
end
end
"bogofilter" has an exit code of "1" if it thinks the message is not
spam, and "0" if it thinks the message is spam.
Hopefully this should give you an idea of the kinds of things that you
can use "bogofilter" for.
AUTHOR
Dave Brown <[email protected]>