.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.3 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "AFEW" "1" "Mar 01, 2026" "3.0.2" "afew"
.SH NAME
afew \- afew Documentation
.sp
\fIafew\fP is an initial tagging script for notmuch mail:
.INDENT 0.0
.IP \(bu 2
\%
.IP \(bu 2
\%
.UNINDENT
.sp
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 \fInotmuch new\fP in an
offlineimap post sync hook or in the notmuch \fIpost\-new\fP hook.
.sp
It can do basic thing such as adding tags based on email headers or maildir
folders, handling killed threads and spam.
.sp
fyi: afew plays nicely with \fIalot\fP, a GUI for notmuch mail ;)
.INDENT 0.0
.IP \(bu 2
\%
.UNINDENT
.sp
Contents:
.SH QUICK START
.sp
The steps to get up and running are:
.INDENT 0.0
.IP \(bu 2
install the afew package
.IP \(bu 2
create the config files
.IP \(bu 2
add a notmuch post\-new hook that calls afew
.UNINDENT
.SS Install
.sp
The following commands will get you going on Debian/Ubuntu systems:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ sudo aptitude install notmuch python\-notmuch dbacl
$ git clone git://github.com/teythoon/afew.git
$ cd afew
$ python setup.py install \-\-prefix=~/.local
.EE
.UNINDENT
.UNINDENT
.sp
Ensure that \fI~/.local/bin\fP is in your path. One way is to add the following to
your \fI~/.bashrc\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
if [ \-d ~/.local/bin ]; then
PATH=$PATH:~/.local/bin
fi
.EE
.UNINDENT
.UNINDENT
.sp
See Installation \%<> for a more detailed guide.
.SS Initial Config
.sp
Make sure that \fI~/.notmuch\-config\fP reads:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[new]
tags=new
.EE
.UNINDENT
.UNINDENT
.sp
Put a list of filters into \fI~/.config/afew/config\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# This is the default filter chain
[SpamFilter]
[KillThreadsFilter]
[ListMailsFilter]
[ArchiveSentMailsFilter]
[InboxFilter]
.EE
.UNINDENT
.UNINDENT
.sp
And create a \fIpost\-new\fP hook for notmuch to call afew:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ notmuchdir=path/to/maildir/.notmuch
$ mkdir \-p \(dq$notmuchdir/hooks\(dq
$ printf > \(dq$notmuchdir/hooks/post\-new\(dq \(aq#!/usr/bin/env sh\en$HOME/.local/bin/afew \-\-tag \-\-new\en\(aq
$ chmod u+x \(dq$notmuchdir/hooks/post\-new\(dq
.EE
.UNINDENT
.UNINDENT
.SS Next Steps
.sp
You can:
.INDENT 0.0
.IP \(bu 2
add extra Filters \%<> for more custom filtering
.IP \(bu 2
make use of the Move Mode \%<> to move your email between folders
.IP \(bu 2
run afew against all your old mail by running \fIafew \-\-tag \-\-all\fP
.IP \(bu 2
start Extending afew \%<> afew
.UNINDENT
.SH INSTALLATION
.SS Requirements
.sp
afew works with python 3.6+, and requires notmuch and its python bindings.
On Debian/Ubuntu systems you can install these by doing:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ sudo aptitude install notmuch python\-notmuch python\-dev python\-setuptools
.EE
.UNINDENT
.UNINDENT
.sp
Note: if you are installing \fInotmuch\fP using Homebrew on macOS, make sure
to run \fB$ brew install \-\-with\-python3 notmuch\fP, because the brew formula
doesn\(aqt install python3 notmuch bindings by default.
.SS Unprivileged Install
.sp
It is recommended to install \fIafew\fP itself inside a virtualenv as an unprivileged
user, either via checking out the source code and installing via setup.py, or
via pip.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# create and activate virtualenv
$ python \-m venv \-\-system\-site\-packages .venv
$ source .venv/bin/activate
# install via pip from PyPI:
$ pip install afew
# or install from source:
$ python setup.py install \-\-prefix=~/.local
.EE
.UNINDENT
.UNINDENT
.sp
You might want to symlink \fI\&.venv/bin/afew\fP somewhere inside your path
(~/bin/ in this case):
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ ln \-snr .venv/bin/afew ~/.bin/afew
.EE
.UNINDENT
.UNINDENT
.SS Building documentation
.sp
Documentation can be built in various formats using Sphinx:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# build docs into build/sphinx/{html,man}
$ python setup.py build_sphinx \-b html,man
.EE
.UNINDENT
.UNINDENT
.SH COMMAND LINE USAGE
.sp
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:
.INDENT 0.0
.TP
.B tag
run the tag filters. See Initial tagging\&.
.TP
.B watch
continuously monitor the mailbox for new files
.TP
.B move\-mails
move mail files between maildir folders
.UNINDENT
.SS Initial tagging
.sp
Basic tagging stuff requires no configuration, just run
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ afew \-\-tag \-\-new
# or to tag *all* messages
$ afew \-\-tag \-\-all
.EE
.UNINDENT
.UNINDENT
.sp
To do this automatically you can add the following hook into your
\fI~/.offlineimaprc\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
postsynchook = ionice \-c 3 chrt \-\-idle 0 /bin/sh \-c \(dqnotmuch new && afew \-\-tag \-\-new\(dq
.EE
.UNINDENT
.UNINDENT
.sp
There is a lot more to say about general filter Configuration \%<>
and the different Filters \%<> provided by afew.
.SS Simulation
.sp
Adding \fI\-\-dry\-run\fP to any \fI\-\-tag\fP or \fI\-\-sync\-tags\fP action prevents
modification of the notmuch db. Add some \fI\-vv\fP goodness to see some
action.
.SS Move Mode
.sp
To invoke afew in move mode, provide the \fI\-\-move\-mails\fP option on the
command line. Move mode will respect \fI\-\-dry\-run\fP, so throw in
\fI\-\-verbose\fP and watch what effects a real run would have.
.sp
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.
.sp
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.
.sp
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
\fI\-\-move\-mails\fP in an offlineimap presynchook and enjoy a clean inbox
in your webinterface/GUI\-client at work.
.sp
Note that in move mode, afew calls \fInotmuch new\fP after moving mails around.
You can use \fIafew \-m \-\-notmuch\-args=\-\-no\-hooks\fP in a pre\-new notmuch hook
to avoid loops.
.sp
For information on how to configure rules for move mode, what you can
do with it and what you can\(aqt, please refer to Move Mode \%<>\&.
.SS Commandline help
.sp
The full set of options is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ 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 \(aq,\(aq [default:
filters specified in afew\(aqs config]
\-d, \-\-dry\-run don\(aqt 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
.EE
.UNINDENT
.UNINDENT
.SH CONFIGURATION
.SS Configuration File
.sp
Customization of tag filters takes place in afew\(aqs config file in
\fI~/.config/afew/config\fP\&.
.SS NotMuch Config
.sp
afew tries to adapt to the new tag that notmuch sets on new email, but has
mostly been developed and used against the \fBnew\fP tag. To use that,
make sure that \fI~/.notmuch\-config\fP contains:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[new]
tags=new
.EE
.UNINDENT
.UNINDENT
.sp
afew reads the notmuch database location from notmuch config. When no database
path is set in notmuch config, afew uses the \fIMAILDIR\fP environment variable
when set, or \fI$HOME/mail\fP as a fallback, like notmuch CLI does. If a relative
path is provided, afew prepends \fI$HOME/\fP to the path in the same manner as
notmuch, which was introduced in version 0.28 of notmuch.
.SS Filter Configuration
.sp
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 \fInotmuch tag\fP command, using
the config file. The default config file is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[SpamFilter]
[KillThreadsFilter]
[ListMailsFilter]
[ArchiveSentMailsFilter]
sent_tag = \(aq\(aq
[InboxFilter]
.EE
.UNINDENT
.UNINDENT
.sp
See the Filters \%<> page for the details of those filters and the custom
arguments they accept.
.sp
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:
.INDENT 0.0
.TP
.B message
text that will be displayed while running this filter if the verbosity is high
enough.
.TP
.B query
the query to use against the messages, specified in standard notmuch format.
Note that you don\(aqt need to specify the \fBnew\fP tag \- afew will add that when
run with the \fI\-\-new\fP flag.
.TP
.B tags
the tags to add or remove for messages that match the query. Tags to add are
preceded by a \fB+\fP and tags to remove are preceded by a \fB\-\fP\&. Multiple tags
are separated by semicolons.
.TP
.B tags_blacklist
if the message has one of these tags, don\(aqt add \fItags\fP to it. Tags are
separated by semicolons.
.UNINDENT
.sp
So to add the \fBdeer\fP tag to any message to or from \fIantelope@deer.com\fP you
could do:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[Filter.1]
query = \(aqantelope@deer.com\(aq
tags = +deer
message = Wild animals ahoy
.EE
.UNINDENT
.UNINDENT
.sp
You can also (in combination with the InboxFilter) have email skip the Inbox
by removing the new tag before you get to the InboxFilter:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[Filter.2]
query = from\(aqpointyheaded@boss.com\(aq
tags = \-new;+boss
message = Message from above
.EE
.UNINDENT
.UNINDENT
.SS Full Sample Config
.sp
Showing some sample configs is the easiest way to understand. The
notmuch initial tagging page \% shows a sample config:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# immediately archive all messages from \(dqme\(dq
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 \(dqnew\(dq messages \(dqinbox\(dq and \(dqunread\(dq
notmuch tag +inbox +unread \-new \-\- tag:new
.EE
.UNINDENT
.UNINDENT
.sp
The (roughly) equivalent set up in afew would be:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[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]
.EE
.UNINDENT
.UNINDENT
.sp
Not that the queries do not generally include \fItag:new\fP because this is implied when afew
is run with the \fI\-\-new\fP flag.
.sp
The differences between them is that
.INDENT 0.0
.IP \(bu 2
the ArchiveSentMailsFilter will add tags specified by \fIsent_tag\fP option
(default \fI\(aq\(aq\fP means add no tags. You may want to set it to \fIsent\fP), as well as
archiving the email. And it will not archive email that has been sent to one
of your own addresses.
.IP \(bu 2
the InboxFilter does not add the \fBunread\fP tag. But most mail clients will
manage the unread status directly in maildir.
.UNINDENT
.SS More Filter Examples
.sp
Here are a few more example filters from github dotfiles:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[Filter.1]
query = \(aqsicsa\-students@sicsa.ac.uk\(aq
tags = +sicsa
message = sicsa
[Filter.2]
query = \(aqfrom:foosoc.ed@gmail.com OR from:GT Silber OR from:lizzie.brough@eusa.ed.ac.uk\(aq
tags = +soc;+foo
message = foosoc
[Filter.3]
query = \(aqfolder:gmail/G+\(aq
tags = +G+
message = gmail spam
# skip inbox
[Filter.6]
query = \(aqto:notmuch@notmuchmail.org AND (subject:emacs OR subject:elisp OR \(dq(defun\(dq OR \(dq(setq\(dq OR PATCH)\(aq
tags = \-new
message = notmuch emacs stuff
# Assuming the following workflow: all messages for projects or releases should be tagged
# as \(dqproject/A\(dq, \(dqproject/B\(dq respectively \(dqrelease/1.0.1\(dq or \(dqrelease/1.2.0\(dq.
#
# 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/.*
.EE
.UNINDENT
.UNINDENT
.SH FILTERS
.sp
The default filter set (if you don\(aqt specify anything in the config) is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[SpamFilter]
[KillThreadsFilter]
[ListMailsFilter]
[ArchiveSentMailsFilter]
[InboxFilter]
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS ArchiveSentMailsFilter
.sp
It extends \fISentMailsFilter\fP with the following feature:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Emails filtered by this filter have the \fBnew\fP tag removed, so will not have
the \fBinbox\fP tag added by the InboxFilter.
.UNINDENT
.UNINDENT
.UNINDENT
.SS DKIMValidityFilter
.sp
This filter verifies DKIM signatures of E\-Mails with DKIM header, and adds \fIdkim\-ok\fP or \fIdkim\-fail\fP tags.
.SS DMARCReportInspectionFilter
.sp
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:
.sp
if there\(aqs any SPF failure in any attachment, tag the message with
\(dqdmarc\-spf\-fail\(dq tag, otherwise tag with \(dqdmarc\-spf\-ok\(dq
.sp
if there\(aqs any DKIM failure in any attachment, tag the message with
\(dqdmarc\-dkim\-fail\(dq tag, otherwise tag with \(dqdmarc\-dkim\-ok\(dq
.SS FolderNameFilter
.sp
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.
.INDENT 0.0
.IP \(bu 2
folder_explicit_list =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Tag mails with tag in only. is a space separated
list, not enclosed in quotes or any other way.
.IP \(bu 2
Empty list means all folders (of course blacklist still applies).
.IP \(bu 2
The default is empty list.
.IP \(bu 2
You may use it e.g. to set tags only for specific folders like \(aqSent\(aq.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
folder_blacklist =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Never tag mails with tag in . is a space separated
list, not enclosed in quotes or any other way.
.IP \(bu 2
The default is to blacklist no folders.
.IP \(bu 2
You may use it e.g. to avoid mails being tagged as \(aqINBOX\(aq when there is the more
standard \(aqinbox\(aq tag.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
folder_transforms =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Transform folder names according to the specified rules before tagging mails.
is a space separated list consisting of
\(aqfolder:tag\(aq style pairs. The colon separates the name of the folder to be
transformed from the tag it is to be transformed into.
.IP \(bu 2
The default is to transform to folder names.
.IP \(bu 2
You may use the rules e.g. to transform the name of your \(aqJunk\(aq folder into your
\(aqspam\(aq tag or fix capitalization of your draft and sent folder:
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
folder_transforms = Junk:spam Drafts:draft Sent:sent
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
folder_lowercases = true
.INDENT 2.0
.IP \(bu 2
Use lowercase tags for all folder names
.UNINDENT
.IP \(bu 2
maildir_separator =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Use to split your maildir hierarchy into individual tags.
.IP \(bu 2
The default is to split on \(aq.\(aq
.IP \(bu 2
If your maildir hierarchy is represented in the filesystem as collapsed dirs,
is used to split it again before applying tags. If your maildir looks
like this:
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[...]
/path/to/maildir/devel.afew/[cur|new|tmp]/...
/path/to/maildir/devel.alot/[cur|new|tmp]/...
/path/to/maildir/devel.notmuch/[cur|new|tmp]/...
[...]
.EE
.UNINDENT
.UNINDENT
.sp
the mails in your afew folder will be tagged with \(aqdevel\(aq and \(aqafew\(aq.
.sp
If instead your hierarchy is split by a more conventional \(aq/\(aq or any
other divider
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[...]
/path/to/maildir/devel/afew/[cur|new|tmp]/...
/path/to/maildir/devel/alot/[cur|new|tmp]/...
/path/to/maildir/devel/notmuch/[cur|new|tmp]/...
[...]
.EE
.UNINDENT
.UNINDENT
.sp
you need to configure that divider to have your mails properly tagged:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
maildir_separator = /
.EE
.UNINDENT
.UNINDENT
.SS HeaderMatchingFilter
.sp
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:
.INDENT 0.0
.IP \(bu 2
header =
.IP \(bu 2
pattern =
.IP \(bu 2
tags =
.UNINDENT
.sp
If you surround a tag with \fI{}\fP then it will be replaced with the named match.
.sp
Some examples are:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[HeaderMatchingFilter.1]
header = X\-Spam\-Flag
pattern = YES
tags = +spam
[HeaderMatchingFilter.2]
header = List\-Id
pattern = <(?P.*)>
tags = +lists;+{list_id}
[HeaderMatchingFilter.3]
header = X\-Redmine\-Project
pattern = (?P.+)
tags = +redmine;+{project}
.EE
.UNINDENT
.UNINDENT
.sp
SpamFilter and ListMailsFilter are implemented using HeaderMatchingFilter, and are
only slightly more complicated than the above examples.
.SS InboxFilter
.sp
This removes the \fBnew\fP tag, and adds the \fBinbox\fP tag, to any message that isn\(aqt
killed or spam. (The new tags are set in your notmuch config, and default to
just \fBnew\fP\&.)
.SS KillThreadsFilter
.sp
If the new message has been added to a thread that has already been tagged
\fBkilled\fP then add the \fBkilled\fP tag to this message. This allows for ignoring
all replies to a particular thread.
.SS ListMailsFilter
.sp
This filter looks for the \fIList\-Id\fP header, and if it finds it, adds a tag
\fBlists\fP and a tag named \fBlists/\fP\&.
.SS MeFilter
.sp
Add filter tagging mail sent directly to any of addresses defined in
Notmuch config file: \fIprimary_email\fP or \fIother_email\fP\&.
Default tag is \fIto\-me\fP and can be customized with \fIme_tag\fP option.
.SS SentMailsFilter
.sp
The settings you can use are:
.INDENT 0.0
.IP \(bu 2
sent_tag =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Add to all mails sent from one of your configured mail addresses, \fIand
not\fP to any of your addresses.
.IP \(bu 2
The default is to add no tag, so you need to specify something.
.IP \(bu 2
You may e.g. use it to tag all mails sent by you as \(aqsent\(aq. 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.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
to_transforms =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Transform \fITo\fP/\fICc\fP/\fIBcc\fP e\-mail addresses to tags according to the
specified rules. is a space separated list consisting
of \%<'user_part@\:domain_part>:tags\(aq style pairs. The colon separates the e\-mail
address to be transformed from tags it is to be transformed into. \(aq:tags\(aq
is optional and if empty, \(aquser_part\(aq is used as tag. \(aqtags\(aq can be
a single tag or semi\-colon separated list of tags.
.IP \(bu 2
It can be used for example to easily tag posts sent to mailing lists which
at this stage don\(aqt have \fIList\-Id\fP field.
.UNINDENT
.UNINDENT
.UNINDENT
.SS SpamFilter
.sp
The settings you can use are:
.INDENT 0.0
.IP \(bu 2
spam_tag =
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Add to all mails recognized as spam.
.IP \(bu 2
The default is \(aqspam\(aq.
.IP \(bu 2
You may use it to tag your spam as \(aqjunk\(aq, \(aqscum\(aq or whatever suits your mood.
Note that only a single tag is supported here.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
Email will be considered spam if the header \fIX\-Spam\-Flag\fP is present.
.SS Customizing filters
.sp
To customize these filters, there are basically two different
possibilities:
.sp
Let\(aqs say you like the SpamFilter, but it is way too polite
.INDENT 0.0
.IP 1. 3
Create an filter object and customize it
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[SpamFilter.0] # note the index
message = meh
.EE
.UNINDENT
.UNINDENT
.sp
The index is required if you want to create a new SpamFilter \fIin
addition to\fP the default one. If you need just one customized
SpamFilter, you can drop the index and customize the default instance.
.INDENT 0.0
.IP 2. 3
Create a new type...
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[ShitFilter(SpamFilter)]
message = I hatez teh spam!
.EE
.UNINDENT
.UNINDENT
.sp
and create an object or two
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[ShitFilter.0]
[ShitFilter.1]
message = Me hatez it too.
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SH MOVE MODE
.SS Configuration Section
.sp
Here is a full sample configuration for move mode:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[MailMover]
folders = INBOX Junk
rename = False
max_age = 15
# rules
INBOX = \(aqtag:spam\(aq:Junk \(aqNOT tag:inbox\(aq:Archive
Junk = \(aqNOT tag:spam AND tag:inbox\(aq:INBOX \(aqNOT tag:spam\(aq:Archive
.EE
.UNINDENT
.UNINDENT
.sp
Below we explain what each bit of this means.
.SS Rules
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
folders = INBOX Junk \(dqSent Mail\(dq
.EE
.UNINDENT
.UNINDENT
.sp
Then you have to specify rules that define move actions of the form
.INDENT 0.0
.INDENT 3.5
.sp
.EX
= [\(aq\(aq:]+
.EE
.UNINDENT
.UNINDENT
.sp
Every mail in the \fI\fP folder that matches a \fI\fP will be moved into the
\fI\fP folder associated with that query. A message that matches
multiple queries will be copied to multiple destinations.
.sp
You can bind as many rules to a maildir folder as you deem necessary. Just add
them as elements of a (whitespace separated) list.
.sp
Please note, though, that you need to specify at least one rule for every folder
given by the \fIfolders\fP option and at least one folder to check in order to use
the move mode.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
INBOX = \(aqtag:spam\(aq:Junk
.EE
.UNINDENT
.UNINDENT
.sp
will bind one rule to the maildir folder \fIINBOX\fP that states that all mails in
said folder that carry (potentially among others) the tag \fBspam\fP are to be moved
into the folder \fIJunk\fP\&.
.sp
With \fI\fP 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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
Junk = \(aqNOT tag:spam AND tag:inbox\(aq:INBOX \(aqNOT tag:spam\(aq:Archive
.EE
.UNINDENT
.UNINDENT
.sp
The above rules will move all mails in \fIJunk\fP that don\(aqt have the \fBspam\fP tag
but do have an \fBinbox\fP tag into the directory \fIINBOX\fP\&. All other mails not
tagged with \fBspam\fP will be moved into \fIArchive\fP\&.
.SS Max Age
.sp
You can limit the age of mails you want to move by setting the \fImax_age\fP option
in the configuration section. By providing
.INDENT 0.0
.INDENT 3.5
.sp
.EX
max_age = 15
.EE
.UNINDENT
.UNINDENT
.sp
afew will only check mails at most 15 days old.
.SS Rename
.sp
Set this option if you are using the \fImbsync\fP IMAP syncing tool.
\fImbsync\fP adds a unique identifier to files\(aq names when it syncs them.
If the \fIrename\fP option is not set, moving files can cause UID conflicts
and prevent \fImbsync\fP from syncing with error messages such as
\(dqMaildir error: duplicate UID 1234\(dq or \(dqUID 567 is beyond highest assigned UID 89\(dq.
.sp
When the option is set, afew will rename files while moving them,
removing the UID but preserving other \fImbsync\fP information.
This allows \fImbsync\fP to assign a new UID to the file and avoid UID conflicts.
.sp
If you are using \fIofflineimap\fP, you can safely ignore this option.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
rename = True
.EE
.UNINDENT
.UNINDENT
.SS Limitations
.sp
\fB(1)\fP Rules don\(aqt manipulate tags.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
INBOX = \(aqNOT tag:inbox\(aq:Archive
Junk = \(aqNOT tag:spam\(aq:INBOX
.EE
.UNINDENT
.UNINDENT
.sp
The above combination of rules might prove tricky, since you might expect
de\-spammed mails to end up in \fIINBOX\fP\&. But since the \fIJunk\fP rule will \fInot\fP add
an \fBinbox\fP tag, the next run in move mode might very well move the matching
mails into \fIArchive\fP\&.
.sp
Then again, if you remove the \fBspam\fP tag and do not set an \fBinbox\fP tag, how
would you come to expect the mail would end up in your INBOX folder after
moving it? ;)
.sp
\fB(2)\fP There is no 1:1 mapping between folders and tags. And that\(aqs 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.
.SH EXTENDING AFEW
.sp
You can put python files in \fI~/.config/afew/\fP and they will be imported by
afew. If you use that python file to define a \fIFilter\fP class and use the
\fIregister_filter\fP decorator then you can refer to it in your filter
configuration.
.sp
So an example small filter you could add might be:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from afew.filters.BaseFilter import Filter
from afew.FilterRegistry import register_filter
PROJECT_MAPPING = {
\(aqfabric\(aq: \(aqdeployment\(aq,
\(aqoldname\(aq: \(aqnew\-name\(aq,
}
@register_filter
class RedmineFilter(Filter):
message = \(aqCreate tag based on redmine project\(aq
query = \(aqNOT tag:redmine\(aq
def handle_message(self, message):
project = message.get_header(\(aqX\-Redmine\-Project\(aq)
if project in PROJECT_MAPPING:
project = PROJECT_MAPPING[project]
self.add_tags(message, \(aqredmine\(aq, project)
.EE
.UNINDENT
.UNINDENT
.sp
We have defined the \fImessage\fP and \fIquery\fP class variables that are used
by the parent class \fIFilter\fP\&. The \fImessage\fP is printed when running with
verbose flags. The \fIquery\fP is used to select messages to run against \- here
we ensure we don\(aqt bother looking at messages we\(aqve already looked at.
.sp
The \fIhandle_message()\fP 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 \fIheader()\fP, \fIfilename()\fP
and \fIget_thread()\fP\&.
.sp
Of the methods inherited from the \fIFilter\fP class the key ones are \fIadd_tags()\fP and
\fIremove_tags()\fP, but read about the Implementation \%<> or just read the source
code to get your own ideas.
.sp
Once you\(aqve defined your filter, you can add it to your config like any other filter:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[RedmineFilter]
.EE
.UNINDENT
.UNINDENT
.SH IMPLEMENTATION
.SS Database Manager
.sp
The design of the database manager was inspired by alots database
manager \fBalot.db.DBManager\fP\&.
.INDENT 0.0
.TP
.B class afew.Database.Database
Convenience wrapper around \fInotmuch\fP\&.
.INDENT 7.0
.TP
.B add_message(path, sync_maildir_flags=False, new_mail_handler=None)
Adds the given message to the notmuch index.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBpath\fP (\fIstr\fP \%) \-\- path to the message
.IP \(bu 2
\fBsync_maildir_flags\fP (\fIbool\fP \%) \-\- if \fITrue\fP notmuch converts the
standard maildir flags to tags
.IP \(bu 2
\fBnew_mail_handler\fP (a function that is called with a
\fBnotmuch.Message\fP object as
its only argument) \-\- callback for new messages
.UNINDENT
.TP
.B Raises
\fBnotmuch.NotmuchError\fP if adding the message fails
.TP
.B Returns
a \fBnotmuch.Message\fP object
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B close()
Closes the notmuch database if it has been opened.
.UNINDENT
.INDENT 7.0
.TP
.B do_query(query)
Executes a notmuch query.
.INDENT 7.0
.TP
.B Parameters
\fBquery\fP (\fIstr\fP \%) \-\- the query to execute
.TP
.B Returns
the query result
.TP
.B Return type
\fBnotmuch.Query\fP
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B get_messages(query, full_thread=False)
Get all messages matching the given query.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBquery\fP (\fIstr\fP \%) \-\- the query to execute using \fBDatabase.do_query()\fP
.IP \(bu 2
\fBfull_thread\fP (\fIbool\fP \%) \-\- return all messages from mathing threads
.UNINDENT
.TP
.B Returns
an iterator over \fBnotmuch.Message\fP objects
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B remove_message(path)
Remove the given message from the notmuch index.
.INDENT 7.0
.TP
.B Parameters
\fBpath\fP (\fIstr\fP \%) \-\- path to the message
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B walk_replies(message)
Returns all replies to the given message.
.INDENT 7.0
.TP
.B Parameters
\fBmessage\fP (\fBnotmuch.Message\fP) \-\- the message to start from
.TP
.B Returns
an iterator over \fBnotmuch.Message\fP objects
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B walk_thread(thread)
Returns all messages in the given thread.
.INDENT 7.0
.TP
.B Parameters
\fBthread\fP (\fBnotmuch.Thread\fP) \-\- the tread you are interested in
.TP
.B Returns
an iterator over \fBnotmuch.Message\fP objects
.UNINDENT
.UNINDENT
.UNINDENT
.SS Filter
.INDENT 0.0
.TP
.B class afew.filters.BaseFilter.Filter(database, **kwargs)
.INDENT 7.0
.TP
.B flush_changes()
(Re)Initializes the data structures that hold the enqueued
changes to the notmuch database.
.UNINDENT
.UNINDENT
.SS Configuration management
.SS Miscellanious utility functions
.INDENT 0.0
.IP \(bu 2
Index \%<>
.IP \(bu 2
Module Index \%<>
.IP \(bu 2
Search Page \%<>
.UNINDENT
.SH Author
Justus Winter
.SH Copyright
afewmail project
.\" End of generated man page.