If the rather simple, standard method for specifying how to split mail
doesn’t allow you to do what you want, you can set
nnmail-split-methods
to nnmail-split-fancy
. Then you can
play with the nnmail-split-fancy
variable.
Let’s look at an example value of this variable first:
;; Messages from the mailer daemon are not crossposted to any of ;; the ordinary groups. Warnings are put in a separate group ;; from real errors. (| ("from" mail (| ("subject" "warn.*" "mail.warning") "mail.misc")) ;; Non-error messages are crossposted to all relevant ;; groups, but we don’t crosspost between the group for the ;; (ding) list and the group for other (ding) related mail. (& (| (any "ding@ifi\\.uio\\.no" "ding.list") ("subject" "ding" "ding.misc")) ;; Other mailing lists… (any "procmail@informatik\\.rwth-aachen\\.de" "procmail.list") (any "SmartList@informatik\\.rwth-aachen\\.de" "SmartList.list") ;; Both lists below have the same suffix, so prevent ;; cross-posting to mkpkg.list of messages posted only to ;; the bugs- list, but allow cross-posting when the ;; message was really cross-posted. (any "bugs-mypackage@somewhere" "mypkg.bugs") (any "mypackage@somewhere" - "bugs-mypackage" "mypkg.list") ;; People… (any "larsi@ifi\\.uio\\.no" "people.Lars_Magne_Ingebrigtsen")) ;; Unmatched mail goes to the catch all group. "misc.misc")
This variable has the format of a split. A split is a (possibly) recursive structure where each split may contain other splits. Here are the possible split syntaxes:
group
If the split is a string, that will be taken as a group name. Normal regexp match expansion will be done. See below for examples.
(field value [- restrict […] ] split [invert-partial])
The split can be a list containing at least three elements. If the first element field (a regexp matching a header) contains value (also a regexp) then store the message as specified by split.
If restrict (yet another regexp) matches some string after field and before the end of the matched value, the split is ignored. If none of the restrict clauses match, split is processed.
The last element invert-partial is optional. If it is
non-nil
, the match-partial-words behavior controlled by the
variable nnmail-split-fancy-match-partial-words
(see below) is
be inverted. (New in Gnus 5.10.7)
(| split …)
If the split is a list, and the first element is |
(vertical
bar), then process each split until one of them matches. A
split is said to match if it will cause the mail message to be
stored in one or more groups.
(& split …)
If the split is a list, and the first element is &
, then
process all splits in the list.
junk
If the split is the symbol junk
, then don’t save (i.e., delete)
this message. Use with extreme caution.
(: function arg1 arg2 …)
If the split is a list, and the first element is ‘:’, then the second element will be called as a function with args given as arguments. The function should return a split.
For instance, the following function could be used to split based on the body of the messages:
(defun split-on-body () (save-excursion (save-restriction (widen) (goto-char (point-min)) (when (re-search-forward "Some.*string" nil t) "string.group"))))
The buffer is narrowed to the header of the message in question when
function is run. That’s why (widen)
needs to be called
after save-excursion
and save-restriction
in the example
above. Also note that with the nnimap backend, message bodies will
not be downloaded by default. You need to set
nnimap-split-download-body
to t
to do that
(see Client-Side IMAP Splitting).
(! func split)
If the split is a list, and the first element is !
, then
split will be processed, and func will be called as a
function with the result of split as argument. func
should return a split.
nil
If the split is nil
, it is ignored.
In these splits, field must match a complete field name.
Normally, value in these splits must match a complete word
according to the fundamental mode syntax table. In other words, all
value’s will be implicitly surrounded by \<...\>
markers,
which are word delimiters. Therefore, if you use the following split,
for example,
(any "joe" "joemail")
messages sent from ‘joedavis@foo.org’ will normally not be filed in ‘joemail’. If you want to alter this behavior, you can use any of the following three ways:
nnmail-split-fancy-match-partial-words
variable
to non-nil
in order to ignore word boundaries and instead the
match becomes more like a grep. This variable controls whether partial
words are matched during fancy splitting. The default value is
nil
.
Note that it influences all value’s in your split rules.
.*
ignores word boundaries in front of
a word. Similarly, if value ends with .*
, word boundaries
in the rear of a word will be ignored. For example, the value
"@example\\.com"
does not match ‘foo@example.com’ but
".*@example\\.com"
does.
nnmail-split-fancy-match-partial-words
is
nil
. Contrarily, if the flag is set, word boundaries are not
ignored even if nnmail-split-fancy-match-partial-words
is
non-nil
. (New in Gnus 5.10.7)
field and value can also be Lisp symbols, in that case
they are expanded as specified by the variable
nnmail-split-abbrev-alist
. This is an alist of cons cells,
where the CAR of a cell contains the key, and the CDR
contains the associated value. Predefined entries in
nnmail-split-abbrev-alist
include:
from
Matches the ‘From’, ‘Sender’ and ‘Resent-From’ fields.
to
Matches the ‘To’, ‘Cc’, ‘Apparently-To’, ‘Resent-To’ and ‘Resent-Cc’ fields.
any
Is the union of the from
and to
entries.
list
Matches the ‘List-ID’, ‘List-Post’, ‘X-Mailing-List’, ‘X-BeenThere’ and ‘X-Loop’ fields.
nnmail-split-fancy-syntax-table
is the syntax table in effect
when all this splitting is performed.
If you want to have Gnus create groups dynamically based on some
information in the headers (i.e., do replace-match
-like
substitutions in the group names), you can say things like:
(any "debian-\\b\\(\\w+\\)@lists.debian.org" "mail.debian.\\1")
In this example, messages sent to ‘debian-foo@lists.debian.org’ will be filed in ‘mail.debian.foo’.
If the string contains the element ‘\\&’, then the previously matched string will be substituted. Similarly, the elements ‘\\1’ up to ‘\\9’ will be substituted with the text matched by the groupings 1 through 9.
Where nnmail-split-lowercase-expanded
controls whether the
lowercase of the matched string should be used for the substitution.
Setting it as non-nil
is useful to avoid the creation of multiple
groups when users send to an address using different case
(i.e., mailing-list@domain vs Mailing-List@Domain). The default value
is t
.
nnmail-split-fancy-with-parent
is a function which allows you to
split followups into the same groups their parents are in. Sometimes
you can’t make splitting rules for all your mail. For example, your
boss might send you personal mail regarding different projects you are
working on, and as you can’t tell your boss to put a distinguishing
string into the subject line, you have to resort to manually moving the
messages into the right group. With this function, you only have to do
it once per thread.
To use this feature, you have to set nnmail-treat-duplicates
and nnmail-cache-accepted-message-ids
to a non-nil
value. And then you can include nnmail-split-fancy-with-parent
using the colon feature, like so:
(setq nnmail-treat-duplicates 'warn ; or delete
nnmail-cache-accepted-message-ids t
nnmail-split-fancy
'(| (: nnmail-split-fancy-with-parent)
;; other splits go here
))
This feature works as follows: when nnmail-treat-duplicates
is
non-nil
, Gnus records the message id of every message it sees
in the file specified by the variable
nnmail-message-id-cache-file
, together with the group it is in
(the group is omitted for non-mail messages). When mail splitting is
invoked, the function nnmail-split-fancy-with-parent
then looks
at the References (and In-Reply-To) header of each message to split
and searches the file specified by nnmail-message-id-cache-file
for the message ids. When it has found a parent, it returns the
corresponding group name unless the group name matches the regexp
nnmail-split-fancy-with-parent-ignore-groups
. It is
recommended that you set nnmail-message-id-cache-length
to a
somewhat higher number than the default so that the message ids are
still in the cache. (A value of 5000 appears to create a file some
300 kBytes in size.)
When nnmail-cache-accepted-message-ids
is non-nil
, Gnus
also records the message ids of moved articles, so that the followup
messages goes into the new group.
Also see the variable nnmail-cache-ignore-groups
if you don’t
want certain groups to be recorded in the cache. For example, if all
outgoing messages are written to an “outgoing” group, you could set
nnmail-cache-ignore-groups
to match that group name.
Otherwise, answers to all your messages would end up in the
“outgoing” group.
If nnmail-debug-splitting
is non-nil
, the mail splitting
code will log all splitting decisions to the ‘*nnmail split*’ buffer.