gurgitate-mail - an easy-to-use mail filter
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
It's generally invoked either through your .forward file:
Or through your .procmailrc file:
:0: | /path/to/gurgitate-mail
(Future versions will, hopefully, be usable as a local delivery agent; a drop-in replacement for ``deliver'' or ``procmail''.)
.gurgitate-rules is a series of Ruby statements, with the following methods and variables available:
savemethod when you specify a folder as ``=folder'' (like Elm). Defaults to ``$HOME/Mail''.
gurgitate-maillogfile. If set to
nil, then no logging is done. Defaults to ``$HOME/.gurgitate.log''.
sendmailprogram. Used by the
forwardmethod. Defaults to ``/usr/lib/sendmail''.
trueif the header
namematches the regular expression
nameis 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.
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
pipereturns the exit code of the program that the message was piped through.
programand 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 change a header's value with
gurgitate-mailto stop processing the email message. If you don't use
gurgitate-mailwill continue processing the same mail again with the next rule. If there isn't a
returnat the end of gurgitate-rules.rb, then
gurgitate-mailwill save the email message in the normal mail spool.
Here are some examples of
gurgitate-mail rules, with
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"],"firstname.lastname@example.org") then pipe("|rcvstore +mailing-list") return end
Any email to a mailing list is piped through ``rcvstore'' to store it into an MH folder.
idiom happens often enough that there's a shorthand for it:
if to =~ /email@example.com/ then pipe("|rcvstore +mailing-list") return end
Pipes the mail to the mailing list through ``rcvstore''.
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:
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
save("=spam") pipe("bogofilter -s") return
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
Dave Brown <firstname.lastname@example.org>