]> git.cworth.org Git - notmuch-wiki/blob - emacstips.mdwn
Add notes on using gnus-alias with notmuch
[notmuch-wiki] / emacstips.mdwn
1 # Tips and Tricks for using notmuch with Emacs
2
3 One of the more popular notmuch message reading clients is
4 **notmuch.el**, an [emacs](http://www.gnu.org/software/emacs/) major
5 mode for interacting with notmuch.  It is included in the notmuch
6 package.  This page goes over some usage tips for using notmuch with
7 Emacs.
8
9 [[!toc levels=2]]
10
11 ## Setup
12
13 To use the Notmuch emacs mode, first add the following line to your
14 `.emacs` rc file:
15
16         (require 'notmuch)
17
18 or you can load the package via autoload:
19
20         (autoload 'notmuch "notmuch" "notmuch mail" t)
21
22 Then, either run "emacs -f notmuch", or execute the command `M-x
23 notmuch` from within a running emacs.
24
25 ## Navigating & reading mails
26
27 When first starting notmuch in emacs, you will be presented with the
28 notmuch "hello" page.  From here you can do searches, see lists of
29 recent searches, saved searches, message tags, help information, etc.
30
31 Executing a search will open a new buffer in `notmuch-search-mode`
32 displaying the search results.  Each line in the search results
33 represents a message thread.  Hitting the '?' key will show help for
34 this mode.
35
36 In general, the 'q' will kill the current notmuch buffer and return
37 you to the previous buffer (sort of like a 'pop').
38
39 In search mode, navigating to a thread and hitting return will then
40 open a new buffer in `notmuch-show-mode`, which will show the actual
41 message contents of the thread.
42
43 ## Sending mail
44
45 In any notmuch mode, you can start a new message by hitting the 'm'
46 key.  To reply to a message or thread, just hit the 'r' key.
47
48 When composing new messages, you will be entered in emacs's
49 `message-mode`, which is a powerful mode for composing and sending
50 messages.  When in message mode, you can type `C-c ?` for help.
51
52 If you would like to use address autocompletion when composing
53 messages, see [address completion](#address_completion).
54
55 When you are ready to send a message, type `C-c C-c`. By default
56 message mode will use your sendmail command to send mail, so make sure
57 that works. One annoying standard configuration of message mode is
58 that it will hide the sent mail in your emacs frame stack, but it will
59 not close it. If you type several mails in an emacs session they will
60 accumulate and make switching between buffers more annoying. You can
61 avoid that behavior by adding `(setq message-kill-buffer-on-exit t)`
62 in your `.emacs` file (or doing `M-x
63 customize-variable<RET>message-kill-buffer-on-exit<RET>`) which will
64 really close the mail window after sending it.
65
66 ## Attaching files
67
68 Using the `M-x mml-attach-file` command, you can attach any file to be
69 sent with your mail. By default this command is bound to the menu item
70 *Attachments--Attach File* with the key binding `C-c C-a`. The
71 variable `mml-dnd-attach-options` (`M-x
72 customize-variable<RET>mml-dnd-attach-options<RET>`) can be set to
73 allow the prompting for various attachment options (such as
74 inline/attachment) if you want to do that.
75
76 For those who prefer a more graphical interface, you can also simply
77 drag and drop files from a file manager into a mail composition window
78 to have them attached. In Ubuntu this works without any modifications
79 if files are dragged from the file manager.
80
81 And for those who prefer working from command line, the following
82 script opens new emacs window with empty message and attaches files
83 mentioned as script arguments. (Note: The script expects that you have
84 `(server-start)` in your `.emacs` file.)
85
86         #!/bin/sh
87         attach_cmds=""
88         while [ "$1" ]; do
89             fullpath=$(readlink --canonicalize "$1")
90             attach_cmds="$attach_cmds (mml-attach-file \"$fullpath\")"
91             shift
92         done
93         emacsclient -a '' -c -e "(progn (compose-mail) $attach_cmds)"
94
95
96 -----
97
98 # Advanced tips and tweaks
99
100 ## Use separate emacs lisp file for notmuch configuration
101
102 Instead of adding notmuch configuration code to `.emacs`, there
103 is an option to collect those to a separate file (which is only
104 loaded when `notmuch` is invoked). To do this, write, for example
105 a file called `~/.emacs.d/my-notmuch.el`:
106
107         ;;; my-notmuch.el -- my notmuch mail configuration
108         ;;;
109         
110         ;;; add here stuff required to be configured *before*
111         ;;; notmuch is loaded;
112
113         ;; uncomment and modify in case some elisp files are not found in load-path
114         ;; (add-to-list 'load-path "~/vc/ext/notmuch/emacs")
115
116         ;;; load notmuch 
117         (require 'notmuch)
118
119         ;;; add here stuff required to be configured *after*
120         ;;; notmuch is loaded;
121
122         ;; uncomment & modify if you want to use external smtp server to send mail
123         ;; (setq smtpmail-smtp-server "smtp.server.tld"
124         ;;       message-send-mail-function 'message-smtpmail-send-it)
125
126 Then, add to `.emacs`:
127
128         (autoload 'notmuch "~/.emacs.d/my-notmuch" "notmuch mail" t)
129
130
131 ## Add a key binding to add/remove/toggle a tag
132
133 The `notmuch-{search,show}-{add,remove}-tag` functions are very useful
134 for making quick tag key bindings.  For instance, here's an example
135 of how to make a key binding to add the "spam" tag and remove the
136 "inbox" tag in notmuch-show-mode:
137
138 In notmuch versions up to 0.11.x
139
140         (define-key notmuch-show-mode-map "S"
141           (lambda ()
142             "mark message as spam"
143             (interactive)
144             (notmuch-show-add-tag "spam")
145             (notmuch-show-remove-tag "inbox")))
146
147 Starting from notmuch 0.12 the functions `notmuch-show-add-tag` and 
148 `notmuch-show-remove-tag` have changed to be more versatile and lost
149 noninteractive use. When upgrading to 0.12 the above needs to be 
150 changed to this:
151
152         (define-key notmuch-show-mode-map "S"
153           (lambda ()
154             "mark message as spam"
155             (interactive)
156             (notmuch-show-tag-message "+spam" "-inbox")))
157
158 You can do the same for threads in `notmuch-search-mode` by just
159 replacing "show" with "search" in the called functions.
160
161 Starting from notmuch 0.12 use `notmuch-search-tag-thread` instead:
162
163         (define-key notmuch-search-mode-map "S"
164           (lambda ()
165             "mark messages in thread as spam"
166             (interactive)
167             (notmuch-show-tag-thread "+spam" "-inbox")))
168
169 Starting from notmuch 0.13 use `notmuch-search-tag` -- it has a little
170 different usage syntax:
171
172         (define-key notmuch-search-mode-map "S"
173           (lambda ()
174             "mark messages in thread as spam"
175             (interactive)
176             (notmuch-search-tag '("+spam" "-inbox"))))
177
178 The definition above makes use of a lambda function, but you could
179 also define a separate function first:
180
181         (defun notmuch-show-tag-spam ()
182           "mark message as spam"
183           (interactive)
184           (notmuch-show-add-tag "spam")
185           (notmuch-show-remove-tag "inbox")))
186         (define-key notmuch-show-mode-map "S" 'notmuch-show-tag-spam)
187
188 (See above for analogy how to apply this for notmuch 0.12 and later)
189
190 Here's a more complicated example of how to add a toggle "deleted"
191 key:
192
193         (define-key notmuch-show-mode-map "d"
194           (lambda ()
195             "toggle deleted tag for message"
196             (interactive)
197             (if (member "deleted" (notmuch-show-get-tags))
198                 (notmuch-show-remove-tag "deleted")
199               (notmuch-show-add-tag "deleted"))))
200
201 And version for notmuch 0.12
202
203         (define-key notmuch-show-mode-map "d"
204           (lambda ()
205             "toggle deleted tag for message"
206             (interactive)
207             (notmuch-show-tag-message
208               (if (member "deleted" (notmuch-show-get-tags))
209                   "-deleted" "+deleted"))))
210
211 ## Adding many tagging keybindings
212
213 If you want to have have many tagging keybindings, you can save the typing
214 the few lines of  boilerplate for every binding (for versions before 0.12,
215 you will need to change notmuch-show-apply-tag-macro).
216
217     (eval-after-load 'notmuch-show
218       '(define-key notmuch-show-mode-map "`" 'notmuch-show-apply-tag-macro))
219
220     (setq notmuch-show-tag-macro-alist
221       (list
222        '("m" "+notmuch::patch" "+notmuch::moreinfo" "-notmuch::needs-review")
223        '("n" "+notmuch::patch" "+notmuch::needs-review" "-notmuch::pushed")
224        '("o" "+notmuch::patch" "+notmuch::obsolete"
225              "-notmuch::needs-review" "-notmuch::moreinfo")
226        '("p" "-notmuch::pushed" "-notmuch::needs-review"
227          "-notmuch::moreinfo" "+pending")
228        '("P" "-pending" "-notmuch::needs-review" "-notmuch::moreinfo" "+notmuch::pushed")
229        '("r" "-notmuch::patch" "+notmuch::review")
230        '("s" "+notmuch::patch" "-notmuch::obsolete" "-notmuch::needs-review" "-notmuch::moreinfo" "+notmuch::stale")
231        '("t" "+notmuch::patch" "-notmuch::needs-review" "+notmuch::trivial")
232        '("w" "+notmuch::patch" "+notmuch::wip" "-notmuch::needs-review")))
233
234     (defun notmuch-show-apply-tag-macro (key)
235       (interactive "k")
236       (let ((macro (assoc key notmuch-show-tag-macro-alist)))
237         (apply 'notmuch-show-tag-message (cdr macro))))
238
239 ## Restore reply-to-all key binding to 'r'
240
241 Starting from notmuch 0.12 the 'r' key is bound to reply-to-sender instead of
242 reply-to-all. Here's how to swap the reply to sender/all bindings in show mode:
243
244         (define-key notmuch-show-mode-map "r" 'notmuch-show-reply)
245         (define-key notmuch-show-mode-map "R" 'notmuch-show-reply-sender)
246
247 And in search mode:
248
249         (define-key notmuch-search-mode-map "r" 'notmuch-search-reply-to-thread)
250         (define-key notmuch-search-mode-map "R" 'notmuch-search-reply-to-thread-sender)
251
252
253 ## How to do FCC/BCC...
254
255 The Emacs interface to notmuch will automatically add an `Fcc`
256 header to your outgoing mail so that any messages you send will also
257 be saved in your mail store. You can control where this copy of the
258 message is saved by setting the variables `message-directory` (which
259 defines a base directory) and `notmuch-fcc-dirs` which defines the
260 subdirectory relative to `message-directory` in which to save the
261 mail. Enter a directory (without the maildir `/cur` ending which
262 will be appended automatically). To customize both variables at the
263 same time, use the fancy command:
264
265         M-x customize-apropos<RET>\(notmuch-fcc-dirs\)\|\(message-directory\)
266
267 This mechanism also allows you to select different folders to be
268 used for the outgoing mail depending on your selected `From`
269 address. Please see the documentation for the variable
270 `notmuch-fcc-dirs` in the customization window for how to arrange
271 this.
272
273 ## How to customize `notmuch-saved-searches`
274
275 When starting notmuch, a list of saved searches and message counts is
276 displayed, replacing the older `notmuch-folders` command. The set of
277 saved searches displayed can be modified directly from the notmuch
278 interface (using the `[save]` button next to a previous search) or by
279 customising the variable `notmuch-saved-searches`.
280
281 An example setting might be:
282
283         (setq notmuch-saved-searches '(("inbox" . "tag:inbox")
284                         ("unread" . "tag:inbox AND tag:unread")
285                         ("notmuch" . "tag:inbox AND to:notmuchmail.org")))
286
287 Of course, you can have any number of saved searches, each configured
288 with any supported search terms (see "notmuch help search-terms").
289
290 Some users find it useful to add `and not tag:delete` to those
291 searches, as they use the `delete` tag to mark messages as
292 deleted. This causes messages that are marked as deleted to be removed
293 from the commonly used views of messages.  Use whatever seems most
294 useful to you.
295
296 ## Viewing HTML messages with an external viewer
297
298 The emacs client can display an HTML message inline using either the
299 `html2text` library or some text browser, like w3m or lynx. This is
300 controlled by the `mm-text-html-renderer` variable.
301
302 The first option is theorically better, because it can generate
303 strings formatted for emacs and do whatever you want, e.g., substitute
304 text inside &lt;b&gt; tags for bold text in the buffer. The library, however
305 is still in a very early development phase and cannot yet process
306 properly many elements, like tables and <style> directives, and even
307 the generated text is often poorly formatted.
308
309 Among the available browsers, w3m seems to do a better job converting
310 the html, and if you have the w3m emacs package, you can use it,
311 instead of the w3m-standalone, and thus preserve the text formatting.
312
313 But if the rendering fails for one reason or another, or if you really
314 need to see the graphical presentation of the HTML message, it can be
315 useful to display the message in an external viewer, such as a web
316 browser. Here's a little script that Keith Packard wrote, which he
317 calls `view-html`:
318
319         #!/bin/sh
320         dir=`mktemp -d`
321         trap "rm -r $dir" 0
322         cat "$@" > "$dir"/msg
323         if munpack -C "$dir" -t < "$dir"/msg 2>&1 | grep 'Did not find'; then
324             sed -n '/[Hh][Tt][Mm][Ll]/,$p' "$dir"/msg > $dir/part1.html
325             rm "$dir"/msg
326         fi
327         for i in "$dir"/part*; do
328             if grep -q -i -e '<html>' -e 'text/html' "$i"; then
329                 iceweasel "$i" &
330                 sleep 3
331                 exit 0
332             fi
333         done
334
335 Save that script somewhere in your `${PATH}`, make it executable,
336 and change the invocation of `iceweasel` to any other HTML viewer if
337 necessary. Then within the emacs client, press '|' to pipe the
338 current message, then type "view-html".
339
340 Keith mentions the following caveat, "Note that if iceweasel isn't
341 already running, it seems to shut down when the script exits. I
342 don't know why."
343
344 ## msmtp, message mode and multiple accounts
345
346 As an alternative to running a mail server such as sendmail or postfix
347 just to send email, it is possible to use
348 [msmtp](http://msmtp.sourceforge.net/). This small application will
349 look like `/usr/bin/sendmail` to a MUA such as emacs message mode, but
350 will just forward the email to an external SMTP server. It's fairly
351 easy to set up and it supports several accounts for using different
352 SMTP servers. The msmtp pages have several examples.
353
354 A typical scenario is that you want to use the company SMTP server
355 for email coming from your company email address, and your personal
356 server for personal email.  If msmtp is passed the envelope address
357 on the command line (the -f/--from option) it will automatically
358 pick the matching account.  The only trick here seems to be getting
359 emacs to actually pass the envelope from.  There are a number of
360 overlapping configuration variables that control this, and it's a
361 little confusion, but setting these three works for me:
362
363  - `mail-specify-envelope-from`: `t`
364
365  - `message-sendmail-envelope-from`: `header`
366
367  - `mail-envelope-from`: `header`
368
369 With that in place, you need a `.msmtprc` with the accounts configured
370 for the domains you want to send out using specific SMTP servers and
371 the rest will go to the default account.
372
373 If you have a hard time getting the above to work for you, as I did,
374 it's also possible to add a message-send-mail-hook in your .emacs to
375 send the from header explicitly as an argument to msmtp as described
376 [here](http://www.emacswiki.org/cgi-bin/wiki/GnusMSMTP#toc2) on the
377 emacswiki.
378
379
380 ## <span id="address_completion">Address completion when composing</span>
381
382 There are currently three solutions to this:
383
384 ### bbdb
385
386 [bbdb](http://bbdb.sourceforge.net) is a contact database for emacs
387 that works quite nicely together with message mode, including
388 address autocompletion.
389
390 ### notmuch database as an address book
391
392 You can also use the notmuch database as a mail address book itself.
393 To do this you need a command line tool that outputs likely address
394 candidates based on a search string.  There are currently three
395 available:
396
397   * The python tool `notmuch_address.py` (`git clone
398     http://commonmeasure.org/~jkr/git/notmuch_addresses.git`) (slower, but
399     no compilation required so good for testing the setup)
400
401   * The vala-based
402     [addrlookup](http://github.com/spaetz/vala-notmuch) (faster, but
403     needs compiling).  The addrlookup binary needs to be compiled.
404     Grab
405     `http://github.com/spaetz/vala-notmuch/raw/static-sources/src/addrlookup.c`
406     and build it with:
407
408             cc -o addrlookup addrlookup.c `pkg-config --cflags --libs gobject-2.0` -lnotmuch
409
410   * Shell/fgrep/perl combination [nottoomuch-addresses.sh](http://www.iki.fi/too/nottoomuch/nottoomuch-addresses/). 
411     This tools maintains it's own address "database" gathered from email
412     files notmuch knows and search from that "database" is done by fgrep(1).
413
414 You can perform tab-completion using any of these programs. Just add the following to your .emacs:
415
416         (require 'notmuch-address)
417         (setq notmuch-address-command "/path/to/address_fetching_program")
418         (notmuch-address-message-insinuate)
419
420 ### Google Contacts
421
422 [GooBook](http://code.google.com/p/goobook/) is a command-line tool for
423 accessing Google Contacts. Install and set it up according to its documentation.
424
425 To use GooBook with notmuch, use this wrapper script and set it up like the
426 programs above.
427
428         #!/bin/sh
429         goobook query "$*" | sed 's/\(.*\)\t\(.*\)\t.*/\2 \<\1\>/' | sed '/^$/d'
430
431 You can add the sender of a message to Google Contacts by piping the message
432 (`notmuch-show-pipe-message`) to `goobook add`.
433
434 ## How to sign/encrypt messages with gpg
435
436 Messages can by signed using gpg by invoking `M-x
437 mml-secure-sign-pgpmime` (or `M-x
438 mml-secure-encrypt-pgpmime`). These functions are available via the
439 standard `message-mode` keybindings `C-c C-m s p` and `C-c C-m c
440 p`. To sign outgoing mail by default, use the `message-setup-hook`
441 in your `.emacs` file:
442
443         ;; Sign messages by default.
444         (add-hook 'message-setup-hook 'mml-secure-sign-pgpmime)
445
446 This inserts the required `<#part sign=pgpmime>` into the beginning
447 of the mail text body and will be converted into a pgp signature
448 when sending (so one can just manually delete that line if signing
449 is not required).
450
451 Alternatively, you may prefer to use `mml-secure-message-sign-pgpmime` instead
452 of `mml-secure-sign-pgpmime` to sign the whole message instead of just one
453 part.
454
455 ### Troubleshooting message-mode gpg support
456
457 - If you have trouble with expired subkeys, you may have encountered
458   emacs bug #7931.  This is fixed in git commit 301ea744c on
459   2011-02-02.  Note that if you have the Debian package easypg
460   installed, it will shadow the fixed version of easypg included with
461   emacs.
462
463 ## Multiple identities using gnus-alias
464
465 gnus-alias allows you to define multiple identities when using
466 message-mode. You can specify the from address, organization, extra
467 headers (including Bcc), extra body text, and signature for each
468 identity. Identities are chosen based on a set of rules. When you are
469 in message mode, you can switch identities using gnus-alias.
470
471 Here is an example configuration.
472
473         ;; Define two identities, "home" and "work"
474         (setq gnus-alias-identity-alist
475               '(("home"
476                  nil ;; Does not refer to any other identity
477                  "John Doe <jdoe@example.net>"
478                  nil ;; No organization header
479                  nil ;; No extra headers
480                  nil ;; No extra body text
481                  "~/.signature")
482                 ("work"
483                  nil
484                  "John Doe <john.doe@example.com>"
485                  "Example Corp."
486                  (("Bcc"        .       "john.doe@example.com"))
487                  nil
488                  "~/.signature.work")))
489         ;; Use "home" identity by default
490         (setq gnus-alias-default-identity "home")
491         ;; Define rules to match work identity
492         (setq gnus-alias-identity-rules
493               '(("work" ("any" "john.doe@\\(example\\.com\\|help\\.example.com\\)" both) "work"))
494         ;; Determine identity when message-mode loads
495         (add-hook 'message-setup-hook 'gnus-alias-determine-identity)