summaryrefslogtreecommitdiffhomepage
path: root/blog/entry/gnus+notmuch.mdwn
blob: bae4055740fee68d1fd4fe1def7c38f8a0812a7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
[[!tag  Emacs notmuch]]

I'd like to share some pointers for using Gnus together with notmuch rather
than notmuch together with notmuch's own Emacs interface, notmuch.el.  I set
about this because I recently realised that I had been poorly reimplementing
lots of Gnus features in my init.el, primarily around killing threads and
catching up groups, supported by a number of complex shell scripts.  I've now
switched over, and I've been able to somewhat simplify what's in my init.el,
and drastically simplify my notmuch configuration outside of Emacs.  I'm
always more comfortable with less Unix and more Lisp when it's feasible.

- The basic settings are `gnus-search-default-engines` and
  `gnus-search-notmuch-remove-prefix`, explained in `(info "(gnus) Searching")`,
  and an entry for your maildir in `gnus-secondary-select-methods`, explained
  in `(info "(gnus) Maildir")`.  Then you will have `G G` and `G g` in the
  group buffer to make and save notmuch searches.

- I think it's important to have something equivalent to
  `notmuch-saved-searches` configured programmatically in your init.el, rather
  than interactively adding each saved search to the group buffer.  This is
  because, as notmuch users know, these saved searches are more like
  permanent, virtual inboxes than searches.  You can learn how to do this by
  looking at how `gnus-group-make-search-group` calls `gnus-group-make-group`.
  I have some code running in `gnus-started-hook` which does something like
  this for each saved search:

    ``` {.el}
    (if (gnus-group-entry group)
        (gnus-group-set-parameter group 'nnselect-specs ...)
      (gnus-group-make-group ...))
    ```

    The idea is that if you update your saved search in your init.el,
    rerunning this code will update the entries in the group buffer.  An
    alternative would be to just kill every nnselect search in the group
    buffer each time, and then recreate them.  In addition to reading
    `gnus-group-make-search-group`, you can look in `~/.newsrc.eld` to see the
    sort of `nnselect-specs` group parameters you'll need your code to
    produce.

    I've very complicated generation of my saved searches from some variables,
    but that's something I had when I was using notmuch.el, too, so perhaps
    I'll describe some of the ideas in there in another post.

- You'll likely want to globally bind a function which starts up Gnus if it's
  not already running and then executes an arbitrary notmuch search.  For that
  you'll want `(unless (gnus-alive-p) (gnus))`, and **not**
  `(unless (gnus-alive-p) (gnus-no-server))`.  This is because you need Gnus
  to initialise nnmaildir before doing any notmuch searches.  Gnus passes
  `--output=files` to notmuch and constructs a summary buffer of results by
  selecting mail that it already knows about with those filenames.

- When you're programmatically generating the list of groups, you might also
  want to programmatically generate a topics topology.  This is how you do
  that:

    ``` {.el}
    (with-current-buffer gnus-group-buffer
      (gnus-topic-mode 0)
      (setq gnus-topic-alist nil gnus-topic topology nil)
      ;; Now push to those two variables.  You can also use
      ;; `gnus-topic-move-matching' to move nnmaildir groups into, e.g.,
      ;; "misc".
      (gnus-topic-mode 1)
      (gnus-group-list-groups))
	```

    If you do this in `gnus-started-hook`, the values for those variables Gnus
    saves into `~/.newsrc.eld` are completely irrelevant and do not need
    backing up/syncing.

- When you want to use `M-g` to scan for new mail in a saved search, you'll
  need to have Gnus also rescan your nnmaildir inbox, else it won't know about
  the filenames returned by notmuch and the messages won't appear.  This is
  similar to the `gnus` vs. `gnus-no-server` issue above.  I'm using `:before`
  advice to `gnus-request-group-scan` to scan my nnmaildir inbox each time any
  nnselect group is to be scanned.

- If you are used to linking to mail from Org-mode buffers, the existing
  support for creating links works fine, and the standard `gnus:` links
  already contain the Message-ID.  But you'll probably want opening the link
  to perform a notmuch search for id:foo rather than trying to use Gnus's own
  jump-to-Message-ID code.  You can do this using `:around` or `:override`
  advice for `org-gnus-follow-link`: look at
  `gnus-group-read-ephemeral-search-group` to do the search, and then call
  `gnus-summary-goto-article`.

I don't think that the above is especially hacky, and don't expect changes to
Gnus to break any of it.  Implementing the above for your own notmuch setup
should get you something close enough to notmuch.el that you can take
advantage of Gnus' unique features without giving up too much of notmuch's
special features.  However, it's quite a bit of work, and you need to be good
at Emacs Lisp.  I'd suggest reading lots of the Gnus manual and determining
for sure that you'll benefit from what it can do before considering switching
away from notmuch.el.

Reading through the Gnus manual, it's been amazing to observe the extent to
which I'd been trying to recreate Gnus in my init.el, quite oblivious that
everything was already implemented for me so close to hand.  Moreover, I used
Gnus ten years ago when I was new to Emacs, so I should have known!  I think
that back then I didn't really understand the idea that Gnus for mail is about
reading mail like news, and so I didn't use any of the features, back then,
that more recently I've been unknowingly reimplementing.