in

mbrt / gmailctl, Hacker News

mbrt / gmailctl, Hacker News

                    [ { filter: { and: [ { to: me }, { from: [email protected] }, { not: spam }, ]          Build Status This utility helps you generate and maintain Gmail filters in a declarative way. It has a (Jsonnet) configuration file that aims to be simpler to write and maintain than using the Gmail web interface, to categorize, label, archive and manage your inbox automatically.

[‘news’] (Motivation) If You have Gmail and have to maintain (like me) a lot of filters, because you want to apply labels, get rid of spam or categorize your emails, then you probably have (like me) a very long list of messy filters. Then the day when you actually want to understand why a certain message got labeled in a certain way comes. You scroll through that horrible mess, you wish you could find-and-replace stuff, check the change before applying it, refactor some filters together … in a way treat them like you treat your code! Gmail allows to import and export filters in XML format. This can be used to maintain them in some better way … but dear Lord, no! Not by hand! That’s what most other tools do: providing some kind of DSL that generate XML filters that can be imported in your settings … by hand [this is the approach of the popularantifuchs/gmail-britta forexample]. Gmail happens to have also a neat API that we can use to automate the import step as well, so to eliminate all manual, slow tasks to be done with the Gmail settings. Build Status This project then exists to provide to your Gmail filters: (Maintainability; [ /… */ ] An easy to understand, declarative, composable language;

    1. A builtin query simplifier, to keep the size of your filters down (Gmail has a limit of (chars per filter); Ability to review your changes before applying them; Automatic update of the settings (no manual import) in seconds. [‘news’] (Install) Make sure to setup your ($ GOPATH) correctly, including the (bin) (subdirectory in your ($ PATH) . go get -u github.com/mbrt/ gmailctl / cmd / gmailctl go install github.com/mbrt/gmailctl/cmd/gmailctl gmailctl init The init will guide you through setting up the Gmail APIs and update your settings without leaving your command line. ‘news’] The easiest way to use gmailctl is to run gmailctl edit . This will open the local .gmailctl / config.jsonnet file in your editor . After you exit the editor the configuration is applied to Gmail. See (Configuration) for the configuration file format. This is the preferred way if you want to start your filters from scratch. (NOTE:) It’s recommended to backup your current configuration before you apply the generated one for the first time. Your current filters will be wiped and replaced with the ones specified in the config file. The diff you’ll get during the first run will probably be pretty big, but from that point on, all changes should generate a small and simple to review diff. Build Status Migrate from another solution

      If you want to preserve your current filters and migrate to a more sane configuration gradually, you can try to use the download command . This will look up at your currently configured filters in Gmail and try to create a configuration file matching the current state. (NOTE:) This functionality is experimental. It’s recommended to download the filters and check that they correspond to the remote ones before making any changes, to avoid surprises. Also note that the configuration file will be quite ugly, as expressions won’t be reconstructed properly, but it should serve as a starting point if you are migrating from other systems. Build Status Example of usage: Build Status (#) download the filters to the default configuration file gmailctl download> ~ /. gmailctl / config.jsonnet (#) check that the diff is empty and no errors are present gmailctl diff (#) happy editing ! gmailctl edit other commands All the available commands (you can also check with

      gmailctl help [ { /message object */ }, // … more messages ] (): apply Apply a configuration file to Gmail settings   debug Shows an annotated version of the configuration   diff Shows a diff between the local configuaration and Gmail settings   download Download filters from Gmail to a local config file   edit Edit the configuration and apply it to Gmail   export Export filters into the Gmail XML format   help Help about any command   init Initialize the Gmail configuration   test Execute config tests // Local variables help reuse config fragments (local) me={   or: [ { to: [email protected] }, { to: [email protected] }, ], }; // The exported configuration starts here {   version: ‘v1alpha3’ ,    // Optional author information (used in exports).   author: {     name: “Pippo Pluto” [list, of, labels] ,     email: ‘[email protected]’   },   rules: [ { filter: { and: [ { list: [email protected] }, { not: me }, // Reference to the local variable ‘me’ ],       },       actions: {         archive: true ,         labels: [‘news’],       },     },   ], }

      Filter operators are prefix of the operands they apply to. In the example above, the filter applies to emails that come from the mail list ‘ [email protected] Go Report Card ‘ AND the recipient is not ‘me’ (which can be ‘ [email protected] Go Report Card ‘OR ‘ ([email protected]) ) . We will see all the features of the configuration file in the following sections. Build Status [ { filter: { and: [ { from: ‘foobar’ }, { not: { or: [ { to: [email protected] }, { to: [email protected] }, ] Search operators Search operators are the same as the ones you find in the Gmail filter interface: Build Status from : the mail comes from the given address

    2. (to [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ] : the mail is delivered to the given address
    3. subject [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ] : the subject contains the given words (has has : the mail contains the given words [‘news’] In addition to those visible in the Gmail interface , you can specify natively the following common operators: (list) : the mail is directed to the given mail list

        (cc) : the mail has the given address as CC destination (bcc) : the mail has the given address as BCC destination [‘news’] One more special function is given if you need to use less common operators (1) () , or want to compose your query manually: Build Status (query) passes the given contents verbatim to the Gmail filter, without escaping or interpreting the contents in any way. [‘news’] (Example: {   version: ‘v1alpha3’ ,   rules: [ { filter: { subject: ‘important mail’ }, actions: { markImportant: true, }, }, { filter: { query: ‘dinner AROUND 5 friday has:spreadsheet’, }, actions: { delete: true, }, }, ], }
        (not [ { name: ‘family’ }, { name: ‘friends’ }, ]) : is true if the sub-expression is false. [‘news’] (Example: {  h version: (‘v1alpha3’) ,   rules: [ { filter: { or: [ { from: ‘foo’ }, { and: [ { list: ‘bar’ }, { not: { to: ‘baz’ } }, ],           },         ],       },       actions: {         markImportant: true ,       },     },   ], } the message comes from “foo”, or
        (local) toMe={   or: [ { to: [email protected] }, { to: [email protected] }, ], }; (local) notToMe={not: toMe}; {   version: ‘v1alpha3’

        ,   rules: [ { filter: { and: [ { from: ‘foobar’ }, notToMe, ],       },       actions: {         delete: true ,       },     },     {       filter: toMe,       actions: {         labels: [‘directed’],       },     },   ], } ‘or to’ [email protected]

        . The (notToMe) filter negates the (toMe) (filter, with a (not) operator. Similarly, the two rules reference the two named filters above. The (name) reference is basically copying the definition of the filter in place.

        The example is effectively equivalent to this one: {   version: ‘v1alpha3’ ,   rules: [ { filter: { and: [ { from: ‘foobar’ }, { not: { or: [ { to: [email protected] }, { to: [email protected] }, ],             },           },         ],       },       actions: {         delete: true ,       },     },     {       filter: {         or: [ { to: [email protected] }, { to: [email protected] }, ],       },       actions: {         labels: [‘directed’],       },     },   ], }

          (star: true [ { name: ‘family’ }, { name: ‘friends’ }, ] : star the message; (markSpam: false [ { name: ‘family’ }, { name: ‘friends’ }, ] : do never mark these messages as spam. Note that setting this field to (true) (is (not) (supported by Gmail (i don’t know why); (markImportant: true) : always mark the message as important, overriding Gmail heuristics;

        1. (markImportant: false) : do never mark the message as important, overriding Gmail heuristics;
        2. category: : force the message into a specific category (supported categories are “personal”, “social”, “updates”, “forums”, “promotions”); (labels: [list, of, labels]) : an array of labels to apply to the message. Note that these labels have to be already present in your settings (they won’t be created automatically), and you can specify multiple labels (normally Gmail (forward: ‘[email protected]’) : forward the message to another email address. The forwarding address must be already in your settings (Forwarding and POP / IMAP> Add a forwarding address). Gmail allows no more than 45 forwarding filters. Only one address can be specified for one filter. [‘news’] (Example: {   version: ‘v1alpha3’ ,   rules: [ { name: ‘family’ }, { name: ‘friends’ }, ],       },     },   ], }

          Example: {   version: ‘v1alpha3’ ,    // optional   labels: [list, of, labels],   rules: [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ],       },     },   ], } $ gmailctl init –reset $ gmailctl init

          If you want to update your existing config to include your existing labels, the best way to get started is to use the download command and copy paste the (labels) (field into your config: $ gmailctl download> /tmp/cfg.jsonnet $ gmailctl edit After the import, verify that your current config does not contain unwanted changes with )

          Example: {   version: ‘v1alpha3’ ,   labels: [ { name: ‘family’ }, { name: ‘friends’ }, ],   rules: [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ], } [‘news’] Tests You can optionally add unit tests to your configuraion. The tests will be executed before applying any changes to the upstream Gmail filters or by running the dedicated (test) subcommand. Tests results can be ignored by passing the – yolo command line option. Tests can be added by using the (tests) field of the main configuration object: Build Status {   version: ‘v1alpha3’ ,   rules: [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ],   tests: [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ], } {    // Reported when the test fails.

            name: “the name of the test” ,    // A list of messages to test against.   messages: [ /… */ ],    // The actions that should be applied to the messages, according to the config.

            actions: {      // Same as the Actions object in the filters.   }, } from: [ { filter: { and: [ { from: ‘foobar’ }, { not: { or: [ { to: [email protected] }, { to: [email protected] }, ] : the sender of the email. to: [] : a list of recipients of the email.

            (cc: [ { name: ‘family’ }, { name: ‘friends’ }, ] : a list of emails in cc.

              bcc: [] : a list of emails in bcc.

            1. lists: [] : a list of mailing lists.
          subject: [‘news’] : the subject of the email.

        3. (body: [‘news’] : the body of the email. [‘news’] all the fields are optional. Remember that each message object represent one email and that the (messages) field of a test is an array of messages. A common mistake is to provide an array of messages thinking that they are only one. Example: Build Status {    (… …   tests: [ { /message object */ }, // … more messages ],     actions: {        (… …     },   ], } {    (… …   tests: [ { /message object */ }, // … more messages ],     actions: {        (… …     },   ], } (Tips and tricks) () Chain filtering Gmail filters are all applied to a mail, if they match, in a non-specified order. So having some if-else alternative is pretty hard to encode by hand. For example sometimes you get interesting stuff from a mail list, but also a lot of garbage too. So, to put some emails with certain contents in one label and the rest somewhere else, you’d have to make multiple filters. Gmail filters however lack if-else constructs, so a way to simulate that is to declare a sequence of filters, where each one negates the previous alternatives. For example you want to: Build Status
        4. mark the email as important if directed to you;

            or if it’s coming from a list of favorite addresses, label as interesting; of if it’s directed to a certain alias, archive it. [‘news’] Luckily you don’t have to do that by hand, thanks to the utility library coming with (gmailctl) . There’s a (chainFilters) function that does exactly that: takes a list of rules and chains them together, so if the first matches, the others are not applied, otherwise the second is checked, and so on … // Import the standard library (local) lib=import ‘gmailctl.libsonnet’

            ; (local) favorite={   or: [ messages: [ { from: “foobar” }, { to: “me” }, ], }; {   version: ‘v1alpha3’ ,   rules: [ { from: [email protected] }, { from: [email protected] }, { list: [email protected] }, ]           // And a chain of filters           lib.chainFilters ([ { from: [email protected] }, { from: [email protected] }, { list: [email protected] }, ]},            },             // Otherwise, if they are directed to my spam alias, archive            {              filter: {to: ‘myself [email protected]’ },              actions: {archive: (true) ,            },          ]), } . The risk you are getting an email where you are not one of the recipients, but a

          [email protected] is, is pretty low, but if you are paranoid you might consider using your full email instead. The config is also easier to read in my opinion. You can also save some typing by introducing a local variable like this: Build Status // Local variable, referenced in all your config. (local) (me=) ‘[email protected]’ ; {   version: ‘v1alpha3’ ,   rules: , }

          is not what you are looking for. This filter in fact (surprisingly) matches all the recipient fields (TO, CC, BCC). To make this work the intended way we have to pull out this trick: (local) directlyTo (recipient)={   and: [ // All directed emails will be marked as important { filter: { to: [email protected] }, actions: { markImportant: true }, }, // Otherwise, if they come from interesting senders, apply a label { filter: favourite, actions: { labels: [‘interesting’], }; So, from all emails where your mail is a recipient, we remove the ones where your mail is in the CC field. This trick is conveniently provided by the (gmailctl) library, so you can use it for example in this way: // Import the standard library (local) lib=import ‘gmailctl.libsonnet’

          ; (local) (me=) ‘[email protected]’ ; {   version: ‘v1alpha3’ ,   rules: , }
          (local) (lib=[ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ] (import) () ‘gmailctl.libsonnet’ [ { name: ‘family’ }, { name: ‘friends’ }, ] ; (local) rules={   {     filter: {to: ‘[email protected]’ },     actions: {labels: [‘directed’]},   },   {     filter: {from: ‘foobar’

          },     actions: {labels: [‘lists/foobar]}, },
          1. If you have labels that are not referenced by any filters (maybe archive labels, or labels applied manually). You have to remember to specify them manually in the list. [‘news’] (Thanks to (legeana) for the idea!

            Multiple Gmail accounts [ { name: ‘family’, color: { background: “#fad165”, text: “#000000”, }, }, ]

            If you need to manage two or more accounts, it’s useful to setup bash aliases this way: (alias) (gmailctlu1=[ { name: ‘family’ }, { name: ‘friends’ }, ] (‘) (gmailctl –config=$ HOME / .gmailctlu1 ‘ [ { filter: { and: [ { from: ‘foobar’ }, { not: { or: [ { to: [email protected] }, { to: [email protected] }, ] Comparison with existing projects gmail-britta Go Report Card has similar motivations and is quite popular. The difference between that project and this one are: (gmail-britta) uses a custom DSL (versus Jsonnet in (gmailctl) () (gmail-britta) is imperative because it allows you to write arbitrary Ruby code in your filters (versus pure declarative for gmailctl [ /… */ ] )

          2. (gmail-britta) allows to write complex chains of filters, but they feel very hardcoded and fails to provide easy ways to write reasonably easy filters (2) . (gmail-britta) exports only to the Gmail XML format. You have to import the filters yourself by using the Gmail web interface, manually delete the filters you updated and import only the new ones. This process becomes tedious very quickly and you will resort to quickly avoid using the tool when in a hurry. (gmailctl) provides you this possibility, but also allows you to review your changes and update the filters by using the Gmail APIs, without you having to do anything manually.
          3. (gmailctl) tries to workaround certain limitations in Gmail (like applying multiple labels with the same filter) and provide a generic query language to Gmail, (gmail-britta) focuses on writing chain filtering and archiving in very few lines. [‘news’] (In short) (gmailctl) takes the declarative approach to Gmail filters Configuration, hoping it stays simpler to read and maintain, does not attempt to simplify complex scenarios with shortcuts (again, hoping the configuration becomes more readable) and provides automatic and fast updates to the filters that will save you time while you are iterating through new versions of your filters. Build Status (Footnotes) (1) See
            Try to write the equivalent of this filter with gmail-britta [ { /message object */ }, // … more messages ] : (local) spam={   or: [ ‘manual-label1’, ‘priority,priority/p1‘, ], }; {   version: ‘v1alpha3’ ,   rules: [ ‘manual-label1’, ‘priority,priority/p1‘, ], }

            require (‘ gmail-britta ‘ (SPAM_EMAILS) (=% w{[email protected] [email protected]}

  • What do you think?

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    GIPHY App Key not set. Please check settings

    Angular 7 : The Ultimate Guide

    Ultimate Excel Training Course – Intro to Advanced Pro