gnus: Fancy Mail Splitting

 
 6.4.6 Fancy Mail Splitting
 --------------------------
 
 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 (SeeClient-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:
 
   1. You can set the ‘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.
 
   2. VALUE beginning with ‘.*’ 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.
 
   3. You can set the INVERT-PARTIAL flag in your split rules of the
      ‘(FIELD VALUE ...)’ types, aforementioned in this section.  If the
      flag is set, word boundaries on both sides of a word are ignored
      even if ‘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.
 
    ‘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.