It took me awhile to give up my local/desktop e-mail client (Claws was my last refuge), but I now use gmail like everyone else.
That said, I still have some habits from a desktop-, yes-I-said-it-Outlook-style workflow, which is using a lot of folders.
In gmail these are called labels, and are basically the same thing.
For example, Iâll have a âlistsâ label for the main email lists Iâm on, a âreviewsâ label for code review notifications, a âjiraâ label for Jira updates, etc.
Hereâs a screenshot of my current filters:

No, Iâm not at inbox zero.
Pros/Cons of Labels
Some people avoid folders/labels all together, which is just fine, as Iâm sure there are good things about that approach. In particular, it seems more inline with inbox zero, which is a solid approach to email processing.
But personally I like the folder-based approach, primarily for batch processing. E.g. when I decide to focus on code reviews, I can work through that label, and stay in that mindset for a dedicated chunk of time.
Granted, a downside of batch processing is that if I either accidentally or semi-purposefully go awhile without focusing on a given label, then a big backlog can build up, and Iâm likely to get behind on replying to things that I should be on top of.
Gmailâs Filter Quirks
So, assuming you are going to use labels, the key is to have filter rules that automatically categorize your incoming mail. E.g. any code review notifications get the âreviewsâ filter applied, etc.
No big deal, gmail supports filter rules, as has Outlook, Claws, and basically every other email client.
However, there are two quirks about gmailâs filters that stymied my initial attempts to setup non-trivial rules:
- There is no âstopâ command
- Editing filters manually in gmail automatically changes their order
Iâll briefly touch on both.
No stop command
The concept of a âstopâ command is useful when you have email that would match multiple rules, but you only want to apply a single one (typically the first).
For example, I might have:
- Code review emails to team A, apply âreviews-aâ
- Code review emails directly to me (but not also team A), apply âreviews-mineâ
E.g. email notifications that are to both team A and me, I want to just keep in âreviews-aâ.
Typically in non-gmail email clients, this is done by appending a âstopâ command to the 1st rule (e.g. after the âmove to âreviews-aâ folderâ command), so that any subsequent rules are skipped.
However, gmail doesnât allow this.
So, the trick/hack is to just use negative filters on the subsequent rules to get the same affect as stopped processing, e.g.:
subject:(code review) to:team-a, apply reviews-a
subject:(code review) to:me -label:reviews-a, apply reviews-mine
Specifically, the 2nd rule has a negative filter, -label:reviews-a
(or -to:team-a
would work as well), which means it wonât apply to any email that also matches the 1st rule.
This hack is really not that complicated, and it is tedious to keep the additional negative filters updated in each subsequent potentially-matching rule, but, at the end of the day, it is an effective way to work around the lack of a âstopâ command.
That said, an extension of this tip that makes it less verbose/more resilient is to leverage that the 1st rule can apply the shouldArchive
command, which will remove the inbox
label (most of my filter rules do this anyway, as skipping the inbox is, for me, the point of using filters).
This means that your 2nd rule can, instead of a negative filter on a previous specific filter (e.g. label:reviews-a
, which is somewhat brittle), it can add a positive filter, label:inbox
, that is very generic, to effectively mean âonly touch mail that has not already been touched/categorized by a rule before meâ.
And so then as long as your rules are in the order you like, youâve effectively made an ad hoc âstop commandâ.
I think the most-cute thing I use this for is my ânoiseâ label, which is âany email that I get, that is not directly addressed to me and not already touched by a previous filter, take out of my inbox, and apply the noise labelâ. These typically end up being organization-wide announcements, none of which are time critical, that I can then batch process when Iâm bored/low-energy. (See below for my noise label definition.)
So, great, we have a âstopâ ability, however, that leads us to the 2nd wrinkle.
Editing Filters Changes Their Order
With the above hack, order of filters becomes important.
However, frustratingly, each time you edit a filter in the gmail UI, the updated filter moves to the bottom of the filter list, which messes up your order.
So if you want to keep your filters in deterministic order, each time you edit one in the UI, you have to fake-edit the others, in a very specific order, to get your desired order back. This is fine with 2 or 3 filters, but becomes impossible with 10+.
Fortunately, there is a trick, which is to not use the gmail UI at all, and instead bulk import/export your filters as XML files.
This is a little clunky, because you have to:
- Make your change in your local
filters.xml
file - Select all your existing filters in gmail UI, delete them
- Upload your updated
filters.xml
filter, import them all
Your filters will then be in the same order as they are in the filters.xml
file, and any nuances you have about filter order will work.
Although an upshot of this is that, since you now have a filters.xml
file locally, you can check it into your home directory git repository, and have it for easy diffing/backup.
Example Filter File
If you start out exporting your existing filters from the gmail UI, the exported XML file is rather ugly and verbose, e.g. it has a lot of long/random looking ids that seem like maybe they are important.
But it turns out many of them are not needed, so eventually I removed the unnecessary cruft, and now have a fairly clean filters.xml
file that I can easily read and maintain.
Here is a trimmed-down example of my current work-related filters.xml
. I deleted most of the labels, and just kept a few basic examples of jira, an email list, an email list that I shouldnât be on, a few review labels, and then my last catch-all noise filter.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006">
<author>
<name>Stephen Haberman</name>
<email>shaberman@linkedin.com</email>
</author>
<!-- jira -->
<entry>
<category term="filter"></category>
<title>jira</title>
<apps:property name="from" value="jirapp"/>
<apps:property name="label" value="jira"/>
<apps:property name="shouldArchive" value="true"/>
</entry>
<!-- lists -->
<entry>
<category term="filter"></category>
<title>lists - support</title>
<apps:property name="to" value="...support...@linkedin.com"/>
<apps:property name="label" value="support"/>
<apps:property name="shouldArchive" value="true"/>
</entry>
<!-- lists - trashed -->
<entry>
<category term="filter"></category>
<title>trash - old support</title>
<apps:property name="hasTheWord" value="to:...@linkedin.com -to:(me OR shaberma@linkedin.com)"/>
<apps:property name="shouldTrash" value="true"/>
</entry>
<!-- reviews -->
<entry>
<category term="filter"></category>
<title>reviews - team-a</title>
<apps:property name="hasTheWord" value="subject:("review request") to:(team-a-reviewers@linkedin.com)"/>
<apps:property name="label" value="reviews-team-a"/>
<apps:property name="shouldArchive" value="true"/>
</entry>
<entry>
<title>reviews - noise</title>
<apps:property name="hasTheWord" value="subject:("review request") -label:reviews-team-a"/>
<apps:property name="label" value="reviews-noise"/>
<apps:property name="shouldArchive" value="true"/>
</entry>
<!-- noise -->
<entry>
<category term="filter"></category>
<title>noise</title>
<apps:property name="hasTheWord" value="label:inbox -to:(shaberma OR me OR my-team@linkedin.com)"/>
<apps:property name="label" value="noise"/>
<apps:property name="shouldArchive" value="true"/>
</entry>
</feed>
Ease of Sharing
A final aspect of using the filters.xml
approach is that it makes sharing filters really easy.
E.g. when a new member joins the team, you can share either your personal or a sort of âteam-defaultsâ filters.xml
that handles the common email lists, alert lists, code review lists, etc., that everyone on the team is on.
This way the new member will have a head start on an organized approach (assuming they want to use a label-based approach, again per personal preference), vs. dealing with a deluge of email and having to just figure it out as they go.
In this vein, if anyone at LinkedIn is interested in my full filters.xml
file (which is engineer-biased, e.g. filters GCNs, autoalerts, etc.) feel free to reach out.