antifuchs/gmail-britta

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# gmail-britta

[![API Docs](https://img.shields.io/badge/api-docs-brightgreen.svg)](https://www.rubydoc.info/github/antifuchs/gmail-britta/master)
[![Gem Version](https://img.shields.io/gem/v/gmail-britta.svg)](https://rubygems.org/gems/gmail-britta)
[![Build Status](https://img.shields.io/travis/antifuchs/gmail-britta/master.svg)](https://travis-ci.org/antifuchs/gmail-britta)

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.

## Motivation

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.

### But how do you make them better?

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](http://gmailblog.blogspot.com/2009/03/new-in-labs-filter-importexport.html).
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.

## Examples

Here are some very simple examples of how gmail-britta can make your
life easier:

### Archiving (or not) semi-important email

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:

``` ruby
GmailBritta.filterset do
  filter {
    has %w{list:discuss@lists.some-side-project.org}
    label "some-side-project"
  }.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.

### Better detection of your own email address

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:

``` ruby
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
```

### If/else chains on filters

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:

``` ruby
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:

1. 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).
2. 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.
3. 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.

## Installation & usage

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:

``` ruby
#!/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 (-:

## Some general tips & tricks

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 short apology to you, dear code-diver

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!
(-:

## Contributing to gmail-britta

* 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

Copyright (c) 2012 Andreas Fuchs. See LICENSE.txt for
further details.