Provided by: afew_3.0.1-5_all bug

NAME

       afew - afew Documentation

       afew is an initial tagging script for notmuch mail:

       • http://notmuchmail.org/http://notmuchmail.org/initial_tagging/

       Its  basic  task  is  to  provide  automatic  tagging each time new mail is registered with notmuch. In a
       classic setup, you might call it after notmuch new in an offlineimap post sync hook  or  in  the  notmuch
       post-new hook.

       It  can  do  basic  thing  such as adding tags based on email headers or maildir folders, handling killed
       threads and spam.

       fyi: afew plays nicely with alot, a GUI for notmuch mail ;)

       • https://github.com/pazz/alot

       Contents:

COMMAND LINE USAGE

       Ultimately afew is a command line tool.  You have to specify  an  action,  and  whether  to  act  on  all
       messages, or only on new messages.  The actions you can choose from are:

       tag    run the tag filters.  See Initial tagging.

       watch  continuously monitor the mailbox for new files

       move-mails
              move mail files between maildir folders

   Initial tagging
       Basic tagging stuff requires no configuration, just run

          $ afew --tag --new
          # or to tag *all* messages
          $ afew --tag --all

       To do this automatically you can add the following hook into your ~/.offlineimaprc:

          postsynchook = ionice -c 3 chrt --idle 0 /bin/sh -c "notmuch new && afew --tag --new"

       There is a lot more to say about general filter Configuration and the different Filters provided by afew.

   Simulation
       Adding --dry-run to any --tag or --sync-tags action prevents modification of the notmuch db. Add some -vv
       goodness to see some action.

   Move Mode
       To invoke afew in move mode, provide the --move-mails option on the command line.  Move mode will respect
       --dry-run, so throw in --verbose and watch what effects a real run would have.

       In move mode, afew will check all mails (or only recent ones) in the configured maildir folders, deciding
       whether they should be moved to another folder.

       The  decision  is  based  on  rules  defined  in your config file. A rule is bound to a source folder and
       specifies a target folder into which a mail will be moved that is matched by an associated query.

       This way you will be able to transfer your sorting principles roughly to the classic folder based maildir
       structure understood by your traditional mail server. Tag your mails with notmuch, call afew --move-mails
       in an offlineimap presynchook and enjoy a clean inbox in your webinterface/GUI-client at work.

       Note that in move mode, afew calls  notmuch  new  after  moving  mails  around.   You  can  use  afew  -m
       --notmuch-args=--no-hooks in a pre-new notmuch hook to avoid loops.

       For  information  on  how  to  configure rules for move mode, what you can do with it and what you can't,
       please refer to Move Mode.

   Commandline help
       The full set of options is:

          $ afew --help
          Usage: afew [options] [--] [query]

          Options:
            -h, --help            show this help message and exit

            Actions:
              Please specify exactly one action.

              -t, --tag           run the tag filters
              -w, --watch         continuously monitor the mailbox for new files
              -m, --move-mails    move mail files between maildir folders

            Query modifiers:
              Please specify either --all or --new or a query string.

              -a, --all           operate on all messages
              -n, --new           operate on all new messages

            General options:
              -C NOTMUCH_CONFIG, --notmuch-config=NOTMUCH_CONFIG
                                  path to the notmuch configuration file [default:
                                  $NOTMUCH_CONFIG or ~/.notmuch-config]
              -e ENABLE_FILTERS, --enable-filters=ENABLE_FILTERS
                                  filter classes to use, separated by ',' [default:
                                  filters specified in afew's config]
              -d, --dry-run       don't change the db [default: False]
              -R REFERENCE_SET_SIZE, --reference-set-size=REFERENCE_SET_SIZE
                                  size of the reference set [default: 1000]
              -T DAYS, --reference-set-timeframe=DAYS
                                  do not use mails older than DAYS days [default: 30]
              -v, --verbose       be more verbose, can be given multiple times

CONFIGURATION

   Configuration File
       Customization of tag filters takes place in afew's config file in ~/.config/afew/config.

   NotMuch Config
       afew tries to adapt to the new tag that notmuch sets on new email, but has mostly been developed and used
       against the new tag.  To use that, make sure that ~/.notmuch-config contains:

          [new]
          tags=new

       afew reads the notmuch database location from notmuch config. When no database path  is  set  in  notmuch
       config,  afew  uses  the MAILDIR environment variable when set, or $HOME/mail as a fallback, like notmuch
       CLI does. If a relative path is provided, afew prepends $HOME/ to the path in the same manner as notmuch,
       which was introduced in version 0.28 of notmuch.

   Filter Configuration
       You can modify filters, and define your own versions of the base Filter that allow you to tag messages in
       a similar way to the notmuch tag command, using the config file.  The default config file is:

          [SpamFilter]
          [KillThreadsFilter]
          [ListMailsFilter]
          [ArchiveSentMailsFilter]
          sent_tag = ''
          [InboxFilter]

       See the Filters page for the details of those filters and the custom arguments they accept.

       You can add filters based on the base filter as well.  These can be  customised  by  specifying  settings
       beneath them.  The standard settings, which apply to all filters, are:

       message
              text that will be displayed while running this filter if the verbosity is high enough.

       query  the  query to use against the messages, specified in standard notmuch format.  Note that you don't
              need to specify the new tag - afew will add that when run with the --new flag.

       tags   the tags to add or remove for messages that match the query. Tags to add are preceded by a  +  and
              tags to remove are preceded by a -.  Multiple tags are separated by semicolons.

       tags_blacklist
              if the message has one of these tags, don't add tags to it. Tags are separated by semicolons.

       So to add the deer tag to any message to or from antelope@deer.com you could do:

          [Filter.1]
          query = 'antelope@deer.com'
          tags = +deer
          message = Wild animals ahoy

       You  can  also  (in  combination  with the InboxFilter) have email skip the Inbox by removing the new tag
       before you get to the InboxFilter:

          [Filter.2]
          query = from'pointyheaded@boss.com'
          tags = -new;+boss
          message = Message from above

   Full Sample Config
       Showing some sample configs is the easiest way to understand.  The notmuch initial tagging page  shows  a
       sample config:

          # immediately archive all messages from "me"
          notmuch tag -new -- tag:new and from:me@example.com

          # delete all messages from a spammer:
          notmuch tag +deleted -- tag:new and from:spam@spam.com

          # tag all message from notmuch mailing list
          notmuch tag +notmuch -- tag:new and to:notmuch@notmuchmail.org

          # finally, retag all "new" messages "inbox" and "unread"
          notmuch tag +inbox +unread -new -- tag:new

       The (roughly) equivalent set up in afew would be:

          [ArchiveSentMailsFilter]

          [Filter.1]
          message = Delete all messages from spammer
          query = from:spam@spam.com
          tags = +deleted;-new

          [Filter.2]
          message = Tag all messages from the notmuch mailing list
          query = to:notmuch@notmuchmail.org
          tags = +notmuch

          [InboxFilter]

       Not  that  the queries do not generally include tag:new because this is implied when afew is run with the
       --new flag.

       The differences between them is that

       • the ArchiveSentMailsFilter will add tags specified by sent_tag option (default '' means  add  no  tags.
         You may want to set it to sent), as well as archiving the email. And it will not archive email that has
         been sent to one of your own addresses.

       • the  InboxFilter  does  not  add  the  unread tag.  But most mail clients will manage the unread status
         directly in maildir.

   More Filter Examples
       Here are a few more example filters from github dotfiles:

          [Filter.1]
          query = 'sicsa-students@sicsa.ac.uk'
          tags = +sicsa
          message = sicsa

          [Filter.2]
          query = 'from:foosoc.ed@gmail.com OR from:GT Silber OR from:lizzie.brough@eusa.ed.ac.uk'
          tags = +soc;+foo
          message = foosoc

          [Filter.3]
          query = 'folder:gmail/G+'
          tags = +G+
          message = gmail spam

          # skip inbox
          [Filter.6]
          query = 'to:notmuch@notmuchmail.org AND (subject:emacs OR subject:elisp OR "(defun" OR "(setq" OR PATCH)'
          tags = -new
          message = notmuch emacs stuff

          # Assuming the following workflow: all messages for projects or releases should be tagged
          # as "project/A", "project/B" respectively "release/1.0.1" or "release/1.2.0".
          #
          # In most cases replies to messages retain their context: the project, the release(s), ..
          #
          # The following config will propagate all project/... or release/... tags from a thread
          # to all new messages.

          [PropagateTagsByRegexInThreadFilter.1]
          propagate_tags = project/.*
          # do not tag spam
          filter = not is:spam

          [PropagateTagsByRegexInThreadFilter.2]
          propagate_tags = release/.*

FILTERS

       The default filter set (if you don't specify anything in the config) is:

          [SpamFilter]
          [KillThreadsFilter]
          [ListMailsFilter]
          [ArchiveSentMailsFilter]
          [InboxFilter]

       The standard filter Configuration can be applied to these filters as well. Though note that most  of  the
       filters  below  set  their own value for message, query and/or tags, and some ignore some of the standard
       settings.

   ArchiveSentMailsFilter
       It extends SentMailsFilter with the following feature:

          • Emails filtered by this filter have the new tag removed, so will not have the inbox tag added by the
            InboxFilter.

   DKIMValidityFilter
       This filter verifies DKIM signatures of E-Mails with DKIM header, and adds dkin-ok or dkin-fail tags.

   DMARCReportInspectionFilter
       DMARC reports usually come in ZIP files. To check the report you have  to  unpack  and  search  thru  XML
       document which is very tedious. This filter tags the message as follows:

       if  there's  any  SPF failure in any attachment, tag the message with "dmarc-spf-fail" tag, otherwise tag
       with "dmarc-spf-ok"

       if there's any DKIM failure in any attachment, tag the message with "dmarc-dkim-fail" tag, otherwise  tag
       with "dmarc-dkim-ok"

   FolderNameFilter
       For each email, it looks at all folders it is in, and uses the path and filename as a tag, for the email.
       So if you have a procmail or sieve set up that puts emails in folders for you, this might be useful.

       • folder_explicit_list = <folder list>

          • Tag  mails  with tag in <folder list> only. <folder list> is a space separated list, not enclosed in
            quotes or any other way.

          • Empty list means all folders (of course blacklist still applies).

          • The default is empty list.

          • You may use it e.g. to set tags only for specific folders like 'Sent'.

       • folder_blacklist = <folder list>

          • Never tag mails with tag in <folder list>. <folder list> is a space separated list, not enclosed  in
            quotes or any other way.

          • The default is to blacklist no folders.

          • You  may  use it e.g. to avoid mails being tagged as 'INBOX' when there is the more standard 'inbox'
            tag.

       • folder_transforms = <transformation rules>

          • Transform folder names according to the  specified  rules  before  tagging  mails.   <transformation
            rules>  is  a  space  separated list consisting of 'folder:tag' style pairs. The colon separates the
            name of the folder to be transformed from the tag it is to be transformed into.

          • The default is to transform to folder names.

          • You may use the rules e.g. to transform the name of your 'Junk' folder into your 'spam' tag  or  fix
            capitalization of your draft and sent folder:

          folder_transforms = Junk:spam Drafts:draft Sent:sent

       • folder_lowercases = true

         • Use lowercase tags for all folder names

       • maildir_separator = <sep>

          • Use <sep> to split your maildir hierarchy into individual tags.

          • The default is to split on '.'

          • If your maildir hierarchy is represented in the filesystem as collapsed dirs, <sep> is used to split
            it again before applying tags. If your maildir looks like this:

          [...]
          /path/to/maildir/devel.afew/[cur|new|tmp]/...
          /path/to/maildir/devel.alot/[cur|new|tmp]/...
          /path/to/maildir/devel.notmuch/[cur|new|tmp]/...
          [...]

       the mails in your afew folder will be tagged with 'devel' and 'afew'.

       If instead your hierarchy is split by a more conventional '/' or any other divider

          [...]
          /path/to/maildir/devel/afew/[cur|new|tmp]/...
          /path/to/maildir/devel/alot/[cur|new|tmp]/...
          /path/to/maildir/devel/notmuch/[cur|new|tmp]/...
          [...]

       you need to configure that divider to have your mails properly tagged:

          maildir_separator = /

   HeaderMatchingFilter
       This  filter  adds  tags to a message if the named header matches the regular expression given.  The tags
       can be set, or based on the match.  The settings you can use are:

       • header = <header_name>

       • pattern = <regex_pattern>

       • tags = <tag_list>

       If you surround a tag with {} then it will be replaced with the named match.

       Some examples are:

          [HeaderMatchingFilter.1]
          header = X-Spam-Flag
          pattern = YES
          tags = +spam

          [HeaderMatchingFilter.2]
          header = List-Id
          pattern = <(?P<list_id>.*)>
          tags = +lists;+{list_id}

          [HeaderMatchingFilter.3]
          header = X-Redmine-Project
          pattern = (?P<project>.*)
          tags = +redmine;+{project}

       SpamFilter and ListMailsFilter are implemented using HeaderMatchingFilter, and  are  only  slightly  more
       complicated than the above examples.

   InboxFilter
       This  removes  the  new  tag, and adds the inbox tag, to any message that isn't killed or spam.  (The new
       tags are set in your notmuch config, and default to just new.)

   KillThreadsFilter
       If the new message has been added to a thread that has already been tagged killed then add the killed tag
       to this message.  This allows for ignoring all replies to a particular thread.

   ListMailsFilter
       This filter looks for the List-Id header, and if  it  finds  it,  adds  a  tag  lists  and  a  tag  named
       lists/<list-id>.

   MeFilter
       Add  filter  tagging mail sent directly to any of addresses defined in Notmuch config file: primary_email
       or other_email.  Default tag is to-me and can be customized with me_tag option.

   SentMailsFilter
       The settings you can use are:

       • sent_tag = <tag>

          • Add <tag> to all mails sent from one of your configured mail addresses,  and  not  to  any  of  your
            addresses.

          • The default is to add no tag, so you need to specify something.

          • You  may  e.g.  use  it  to  tag  all  mails  sent  by you as 'sent'. This may make special sense in
            conjunction with a mail client that is able to not only search for threads but individual  mails  as
            well.

       • to_transforms = <transformation rules>

          • Transform  To/Cc/Bcc  e-mail  addresses  to  tags  according to the specified rules. <transformation
            rules> is a space separated list consisting of 'user_part@domain_part:tags' style pairs.  The  colon
            separates  the  e-mail  address to be transformed from tags it is to be transformed into. ':tags' is
            optional and if empty, 'user_part' is used as tag.   'tags'  can  be  a  single  tag  or  semi-colon
            separated list of tags.

          • It  can be used for example to easily tag posts sent to mailing lists which at this stage don't have
            List-Id field.

   SpamFilter
       The settings you can use are:

       • spam_tag = <tag>

          • Add <tag> to all mails recognized as spam.

          • The default is 'spam'.

          • You may use it to tag your spam as 'junk', 'scum' or whatever suits your mood.   Note  that  only  a
            single tag is supported here.

       Email will be considered spam if the header X-Spam-Flag is present.

   Customizing filters
       To customize these filters, there are basically two different possibilities:

       Let's say you like the SpamFilter, but it is way too polite

       1. Create an filter object and customize it

          [SpamFilter.0] # note the index
          message = meh

       The  index is required if you want to create a new SpamFilter in addition to the default one. If you need
       just one customized SpamFilter, you can drop the index and customize the default instance.

       2. Create a new type...

          [ShitFilter(SpamFilter)]
          message = I hatez teh spam!

       and create an object or two

          [ShitFilter.0]
          [ShitFilter.1]
          message = Me hatez it too.

       You can provide your own filter implementations too. You have to register your filters via entry  points.
       See the afew setup.py for examples on how to register your filters. To add your filters, you just need to
       install your package in the context of the afew application.

MOVE MODE

   Configuration Section
       Here is a full sample configuration for move mode:

          [MailMover]
          folders = INBOX Junk
          rename = False
          max_age = 15

          # rules
          INBOX = 'tag:spam':Junk 'NOT tag:inbox':Archive
          Junk = 'NOT tag:spam AND tag:inbox':INBOX 'NOT tag:spam':Archive

       Below we explain what each bit of this means.

   Rules
       First you need to specify which folders should be checked for mails that are to be moved (as a whitespace
       separated list). Folder names containing whitespace need to be quoted:

          folders = INBOX Junk "Sent Mail"

       Then you have to specify rules that define move actions of the form

          <src> = ['<qry>':<dst>]+

       Every  mail  in the <src> folder that matches a <qry> will be moved into the <dst> folder associated with
       that query.  A message that matches multiple queries will be copied to multiple destinations.

       You can bind as many rules to a maildir folder as you deem necessary. Just add  them  as  elements  of  a
       (whitespace separated) list.

       Please  note,  though,  that  you need to specify at least one rule for every folder given by the folders
       option and at least one folder to check in order to use the move mode.

          INBOX = 'tag:spam':Junk

       will bind one rule to the maildir folder INBOX that states that all  mails  in  said  folder  that  carry
       (potentially among others) the tag spam are to be moved into the folder Junk.

       With  <qry> being an arbitrary notmuch query, you have the power to construct arbitrarily flexible rules.
       You can check for the absence of tags and look out for combinations of attributes:

          Junk = 'NOT tag:spam AND tag:inbox':INBOX 'NOT tag:spam':Archive

       The above rules will move all mails in Junk that don't have the spam tag but do have an  inbox  tag  into
       the directory INBOX. All other mails not tagged with spam will be moved into Archive.

   Max Age
       You  can  limit  the  age  of  mails  you want to move by setting the max_age option in the configuration
       section. By providing

          max_age = 15

       afew will only check mails at most 15 days old.

   Rename
       Set this option if you are using the mbsync IMAP syncing tool.  mbsync adds a unique identifier to files'
       names when it syncs them.  If the rename option is not set, moving files  can  cause  UID  conflicts  and
       prevent  mbsync  from syncing with error messages such as "Maildir error: duplicate UID 1234" or "UID 567
       is beyond highest assigned UID 89".

       When the option is set, afew will rename files while moving them, removing the UID but  preserving  other
       mbsync information.  This allows mbsync to assign a new UID to the file and avoid UID conflicts.

       If you are using offlineimap, you can safely ignore this option.

          rename = True

   Limitations
       (1) Rules don't manipulate tags.

          INBOX = 'NOT tag:inbox':Archive
          Junk = 'NOT tag:spam':INBOX

       The  above  combination of rules might prove tricky, since you might expect de-spammed mails to end up in
       INBOX. But since the Junk rule will not add an inbox tag, the next run in move mode might very well  move
       the matching mails into Archive.

       Then again, if you remove the spam tag and do not set an inbox tag, how would you come to expect the mail
       would end up in your INBOX folder after moving it? ;)

       (2)  There  is  no 1:1 mapping between folders and tags. And that's a feature. If you tag a mail with two
       tags and there is a rule for each of them, both rules will apply.  Your mail  will  be  copied  into  two
       destination folders, then removed from its original location.

EXTENDING AFEW

       You  can  put  python files in ~/.config/afew/ and they will be imported by afew.  If you use that python
       file to define a Filter class and use the register_filter decorator then you can  refer  to  it  in  your
       filter configuration.

       So an example small filter you could add might be:

          from afew.filters.BaseFilter  import Filter
          from afew.FilterRegistry import register_filter

          PROJECT_MAPPING = {
              'fabric': 'deployment',
              'oldname': 'new-name',
          }

          @register_filter
          class RedmineFilter(Filter):
              message = 'Create tag based on redmine project'
              query = 'NOT tag:redmine'

              def handle_message(self, message):
                  project = message.get_header('X-Redmine-Project')
                  if project in PROJECT_MAPPING:
                      project = PROJECT_MAPPING[project]
                  self.add_tags(message, 'redmine', project)

       We  have  defined  the  message  and query class variables that are used by the parent class Filter.  The
       message is printed when running with verbose flags.  The query is used to select messages to run  against
       - here we ensure we don't bother looking at messages we've already looked at.

       The  handle_message()  method  is  the  key  one to implement.  This will be called for each message that
       matches the query.  The argument is a notmuch message object and the key methods used by the afew filters
       are get_header(), get_filename() and get_thread().

       Of the methods inherited from the Filter class the key ones are add_tags() and  remove_tags(),  but  read
       about the Implementation or just read the source code to get your own ideas.

       Once you've defined your filter, you can add it to your config like any other filter:

          [RedmineFilter]

IMPLEMENTATION

   Database Manager
       The design of the database manager was inspired by alots database manager alot.db.DBManager.

       class afew.Database.Database
              Convenience wrapper around notmuch.

              add_message(path, sync_maildir_flags=False, new_mail_handler=None)
                     Adds the given message to the notmuch index.

                     Parameterspath (str) -- path to the message

                            • sync_maildir_flags  (bool)  -- if True notmuch converts the standard maildir flags
                              to tags

                            • new_mail_handler (a function that is called with a notmuch.Message object  as  its
                              only argument) -- callback for new messages

                     Raises notmuch.NotmuchError if adding the message fails

                     Returns
                            a notmuch.Message object

              close()
                     Closes the notmuch database if it has been opened.

              do_query(query)
                     Executes a notmuch query.

                     Parameters
                            query (str) -- the query to execute

                     Returns
                            the query result

                     Return type
                            notmuch.Query

              get_messages(query, full_thread=False)
                     Get all messages mathing the given query.

                     Parametersquery (str) -- the query to execute using Database.do_query()full_thread (bool) -- return all messages from mathing threads

                     Returns
                            an iterator over notmuch.Message objects

              remove_message(path)
                     Remove the given message from the notmuch index.

                     Parameters
                            path (str) -- path to the message

              walk_replies(message)
                     Returns all replies to the given message.

                     Parameters
                            message (notmuch.Message) -- the message to start from

                     Returns
                            an iterator over notmuch.Message objects

              walk_thread(thread)
                     Returns all messages in the given thread.

                     Parameters
                            thread (notmuch.Thread) -- the tread you are interested in

                     Returns
                            an iterator over notmuch.Message objects

   Filter
       class afew.filters.BaseFilter.Filter(database, **kwargs)

              flush_changes()
                     (Re)Initializes the data structures that hold the enqueued changes to the notmuch database.

   Configuration management
   Miscellanious utility functionsIndexModule IndexSearch Page

AUTHOR

       Justus Winter

COPYRIGHT

       afewmail project

3.0.1                                             Sep 27, 2023                                           AFEW(1)