This library helps you generate XML that you can import into gmail's filter settings. It makes it more pleasant to write simple (and even complex) filter chains.
As a user of the internet, you probably use gmail, and you probably get a lot of Email - I do. Just like me, you're also likely to have a lot of filters that were once supposed to keep your inbox clean. But every time you click "Filter messages like this", you remember the enormous list of filters you have and how it is only ever going to make things worse in the long run.
As a programmer, I write code. As a metaprogrammer, I write code that writes code. If only gmail filters could be written by a program. Oh wait, they can. There's an import & export function for gmail filters. These filters are exported as XML, and the import in turn takes XML files. What this library does is generate XML that you can import.
Here are some very simple examples of how gmail-britta can make your life easier:
Imagine you're on a discussion mailing list that you skim from time to time - so you want to label email to that list, and archive email from it so it doesn't clog up your inbox. Now, from time to time someone will Cc: you an important message, and you don't want to miss these - what to do?
Naively, you define a filter like this:
list:discuss@lists.some-side-project.org !to:thisisme@mydomain.com
-> Archive, Label "some-side-project"
But this also means email addressed to you but also sent to that list will be missing the "some-side-project" label. This means you need two filters!
list:discuss@lists.some-side-project.org !to:thisisme@mydomain.com
-> Archive
list:discuss@lists.some-side-project.org
-> Label "some-side-project"
Now this can get pretty hairy pretty quickly; and if you ever have to change the filter (e.g., the list changes email addresses), you have to change two filters! Ugh.
With gmail-britta, it's just this:
GmailBritta.filterset do
filter {
has %w{list:discuss@lists.some-side-project.org}
}.archive_unless_directed
end
That's it - this little piece of ruby code will generate these two filters; and if the list address changes, you just re-import these filters. Easy.
If you have issued a search for to:me
on gmail in the last few
months (and you get Email from iCloud nee MobileMe users), you'll
notice that to:me
also matches the "me" in example@me.com
. This is
very frustrating mostly because any filter as above that matches on
to:me
will now also not archive email sent from a me.com
account. With gmail-britta, you can define a set of emails that are
yours, and archive_unless_directed
will generate a filter that
matches on those:
GmailBritta.filterset(:me => ['thisisme@my-private.org', 'this-is-me@bigco.example.com']) do
filter {
has %w{list:discuss@lists.some-side-project.org}
}.archive_unless_directed
end
There are instances where you can't only match on the mailing list - sometimes interesting stuff will be sent to one list (that you want to read), and lots of unnecessary silliness will be sent there too. So, to put email with a certain subject into one label, and to put all the rest into another, you have to make multiple filters. But gmail lacks if/else in filters - you have to duplicate and correctly negate each filter's condition in the next one. Luckily, you have gmail-britta to help you out there:
GmailBritta.filterset do
filter {
has %w{list:robots@bigco.com subject:Important}
label 'work/robots/important'
# Do not archive
}.otherwise {
has %w{list:robots@bigco.com subject:Chunder}
label 'work/robots/irrelevant'
}.archive_unless_directed(:mark_read => true).otherwise {
has %w{list:robots@bigco.com subject:Semirelevant}
label 'work/robots/meh'
}.archive_unless_directed
end
A lot of things going on here! First, I hope you notice that this
looks similar to an if/else-if statement. Second, you may notice the
liberal application of .archive_unless_directed
, with an optional
:mark_read
parameter. Third, do check out the XML generated by this,
it's pretty horriffic - but the filters do exactly what the code says:
- If the email is sent to that list and has "Important" in the subject, it gets labeled with the work/robots/important label, and won't be archived (unless another filter further down does archive that email).
- If the email does not match all the above criteria, but is sent to that list and has "Chunder" in the subject, label it irrelevant, archive it and mark the email as read.
- If the email does not match all the above criteria, but is sent to that list and has "Semirelevant" in the subject, label it "meh" and archive it, but don't mark it as read.
Best to use gmail-britta from a ruby script; but install the gem first:
gem install gmail-britta
Or include it in your Gemfile:
gem 'gmail-britta'
This is a simple script that generates filters for you:
#!/bin/env ruby
require 'rubygems'
require 'gmail-britta'
fs = GmailBritta.filterset(:me => ['thisisme@my-private.org']) do
filter {
has %w{from:asf@boinkor.net}
label 'from-the-author-of-gmail-britta'
never_spam
}
end
puts fs.generate
Running this script will write to stdout the filter XML that you need. Redirect that to a file and upload it on the bottom of your gmail filter settings, and you'll label email from me and archive it unless I email you specifically. Not that useful, but with your own filters and the recipes above, you should be able to make it work (-:
Here are some things to note when performing filter-fu with gmail:
- A filter condition tops out at 1500 chars, apparently. This fits a decent amount of conditions, but something to be careful about. There is no check in gmail-britta against this, but Gmail will refuse to import (or drop) filters that violate this.
- If you use
archive_unless_directed
heavily, you almost certainly want to check the "Don't override filters" box in Gmail's Inbox preferences.
A lot of this is a bit hacky (particularly the filter condition merge logic), as it started as a oneoff ruby script - very sorry for any amateurish code you may encounter. There are few tests, but so far, it does work for me. Let me know if this made your life harder or easier! (-:
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
- Fork the project.
- Start a feature/bugfix branch.
- Commit and push until you are happy with your contribution.
- Make sure to add tests for it. (Note that are only very few tests yet. I would totally appreciate if you started fleshing out this suite, but I wouldn't expect you to add much of anything.)
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright (c) 2012 Andreas Fuchs. See LICENSE.txt for further details.