summaryrefslogtreecommitdiff
path: root/.emacs.d/notmuch-config.el
blob: 579b314bff94fa4f541056b9029f868d8f3a8e67 (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
;;; init-notmuch.el --- Sean's notmuch-emacs config -*- lexical-binding: t -*-

;;; Code:

(require 'cl-lib)

(require 'notmuch)
(require 'notmuch-hello)
(require 'notmuch-message)


;;;; Preferences and variables

(setq notmuch-show-all-tags-list t
      notmuch-tagging-keys '(("u" ("+unread") "Mark as unread")
                             ("s" ("-unread" "+spam") "Mark as spam")

                             ;; 'm' for 'mute'
                             ("m" ("-unread" "+spw::killed") "Kill thread")

                             ;; for work mail sent to a personal
                             ;; address, or similar
                             ("w" ("+spw::work") "Mark as work-related")

                             ("b" ("+spw::browse") "Mark for browsing")
                             ("d" ("-unread" "+deleted") "Send to trash")
                             ("f" ("-unread" "+flagged") "Unread->flagged")
                             ("F" ("-flagged") "Unflag message"))

      ;; default is t, but given that notmuch searches run to the
      ;; beginning of time, and we are likely to want recent mail, we want
      ;; newer e-mails at the top
      notmuch-search-oldest-first nil

      ;; Don't collapse cited text.  We ought to be able to just remove
      ;; `notmuch-wash-excerpt-citations' from
      ;; `notmuch-show-insert-text/plain-hook', but that function is also
      ;; responsible for colouring cited text (this is an upstream bug:
      ;; that function does the colouring for performance reasons but the
      ;; right answer is to use fontlocking, not overlays, for the
      ;; colouring)
      notmuch-wash-citation-lines-prefix 10000
      notmuch-wash-citation-lines-suffix 10000

      send-mail-function 'sendmail-send-it

      ;; always decrypt & verify PGP parts
      notmuch-crypto-process-mime t

      ;; have Emacs set envelope-from to bypass my MTA rewriting of
      ;; user@localhost
      mail-specify-envelope-from t
      mail-envelope-from 'header
      message-sendmail-envelope-from 'header

      notmuch-archive-tags '("-unread")
      notmuch-maildir-use-notmuch-insert t
      notmuch-fcc-dirs "sent -unread"

      ;; when 'unread' is being used as an inbox, want manual resolution
      ;; of messages
      notmuch-show-mark-read-function 'ignore
      notmuch-show-mark-read-tags nil
      ;; but always resolve when I write a reply
      notmuch-message-replied-tags '("-unread" "+replied")

      notmuch-mua-user-agent-function 'notmuch-mua-user-agent-full

      ;; for compatibility
      message-forward-before-signature nil
      message-forward-as-mime nil
      message-forward-included-headers
      "^\\(From\\|To\\|Cc\\|Subject\\|Date\\|Message-ID\\):"
      message-make-forward-subject-function #'message-forward-subject-fwd

      notmuch-mua-cite-function #'message-cite-original-without-signature
      message-citation-line-function #'message-insert-formatted-citation-line
      message-citation-line-format "On %a %d %b %Y at %I:%M%p %Z, %N wrote:\n"

      ;; default dir for saving attachments
      mm-default-directory "~/tmp/"

      ;; encrypt messages to me too, so I can read copies in my sent mail folder
      mml-secure-openpgp-encrypt-to-self t

      mml-secure-openpgp-sign-with-sender t

      message-kill-buffer-on-exit t)

;; these three vars get set in notmuch-groups.el
(defvar spw/lists-readall nil
  "Lists where I want to read all posts as if they're addressed
directly to me -- these get inserted into my main inbox
views.")
(defvar spw/lists-browse nil
  "Lists I want to read like newsgroups, though with no expiry
and manual catchup.

Two ways to read:

1. Access saved searches from `notmuch-hello', then use
`notmuch-search-filter' to look for something in particular.

2. Access using `spw/next-unread-group' to read new postings.")
(defvar spw/lists-archiveonly nil
  "Lists for which I'm subscribed only because I want to
    archive all postings.  Sieve script should be configured to
    mark as read.")
;; indeed, marking as read of incoming mail should generally occur
;; server-side


;;;; Bindings and advising commands

(advice-add 'notmuch-tree-archive-thread :after #'notmuch-tree-next-thread)

(define-key notmuch-message-mode-map "\C-c\C-s" #'message-goto-subject)

(define-key notmuch-show-mode-map "\C-cg.g" #'spw/notmuch-import-gpg)
(define-key notmuch-show-mode-map "\C-cg.a" #'spw/notmuch-show-apply-part-to-project)

;; we want these not to be adjacent keys
(define-key notmuch-search-mode-map [f5]	#'spw/spam-message)
(define-key notmuch-search-mode-map "S"		#'spw/spam-message)
(define-key notmuch-search-mode-map [f7]	#'spw/kill-thread)
(define-key notmuch-search-mode-map "\M-k"	#'spw/kill-thread)
(define-key notmuch-search-mode-map [f9]	#'spw/next-unread-group)

;; ditto
(define-key notmuch-show-mode-map   [f5]	#'spw/spam-message)
(define-key notmuch-show-mode-map   "S"		#'spw/spam-message)
(define-key notmuch-show-mode-map   [f7]	#'spw/kill-thread)
(define-key notmuch-show-mode-map   "\M-k"	#'spw/kill-thread)

;; ditto
(define-key notmuch-tree-mode-map   [f5]	#'spw/spam-message)
(define-key notmuch-tree-mode-map   "S"		#'spw/spam-message)
(define-key notmuch-tree-mode-map   [f7]	#'spw/kill-thread)
(define-key notmuch-tree-mode-map   "\M-k"	#'spw/kill-thread)
(define-key notmuch-tree-mode-map   [f9]	#'spw/next-unread-group)

(define-key notmuch-hello-mode-map  [f9]	#'spw/next-unread-group)

(define-key notmuch-tree-mode-map   "\C-cgo"	#'spw/notmuch-reader)
(define-key notmuch-tree-mode-map   "\C-cC"	#'spw/notmuch-catchup)

(define-key notmuch-show-mode-map   "\C-cgo"	#'spw/notmuch-reader)
(define-key notmuch-search-mode-map "\C-cC"	#'spw/notmuch-catchup)

(define-key notmuch-show-mode-map   " "         #'spw/notmuch-show-advance-and-archive)

(define-key notmuch-message-mode-map [remap notmuch-mua-send-and-exit]
  #'spw/notmuch-mua-send-and-exit)

(define-key notmuch-show-mode-map "\C-cgf"
  #'spw/notmuch-show-filter-thread-patches)
(define-key notmuch-show-mode-map "\C-cgi"
  #'spw/notmuch-show-with-remote-images)


;;;; Commands

(defun spw/notmuch-import-gpg ()
  (interactive)
  (when (get-buffer "*notmuch-pipe*")
    (with-current-buffer "*notmuch-pipe*"
      (let ((buffer-read-only nil))
        (erase-buffer))))
  (notmuch-show-pipe-message t "gpg --decrypt | gpg --import")
  (display-buffer "*notmuch-pipe*"))

;; unlike `notmuch-extract-thread-patches' and
;; `notmuch-extract-message-patches', it does not make sense to
;; check out a branch when performing an action which will not make
;; a commit.  If that's wanted, the code which calls
;; `spw/notmuch-show-apply-part-projectile' should perform the checkout
(defun spw/notmuch-show-apply-part-to-project ()
  (interactive)
  (let ((default-directory (expand-file-name (project-prompt-project-dir))))
    (notmuch-show-apply-to-current-part-handle
     (lambda (handle)
       (mm-pipe-part handle "git apply")))))

(defun spw/kill-thread ()
  (interactive)
  (cl-case major-mode
    (notmuch-show-mode
     (notmuch-show-tag '("+spw::killed"))
     (notmuch-show-archive-thread-then-next))
    (notmuch-tree-mode
     (notmuch-tree-close-message-window)
     (notmuch-tree-tag '("+spw::killed"))
     (notmuch-tree-archive-thread)
     (unless (notmuch-tree-get-match)
       (notmuch-tree-next-matching-message))
     (notmuch-tree-show-message nil))
    (notmuch-search-mode
     ;; here we want to avoid tagging every message in the thread to reduce
     ;; pressure on nmbug-spw.git -- so we just pick the first of the matched
     ;; messages
     (notmuch-tag
      (car (split-string (car (plist-get (notmuch-search-get-result) :query))))
      '("+spw::killed"))
     (notmuch-search-archive-thread)))
  (message "Thread killed"))

(defun spw/spam-message ()
  (interactive)
  (cl-case major-mode
    (notmuch-show-mode
     (notmuch-show-tag '("-unread" "+spam"))
     (notmuch-show-archive-message-then-next-or-next-thread))
    (notmuch-tree-mode
     (notmuch-tree-tag '("-unread" "+spam"))
     (notmuch-tree-next-matching-message)))
  (message "Message marked as spam"))

(defun spw/notmuch-reader ()
  (interactive)
  (with-current-buffer (or notmuch-tree-message-buffer (current-buffer))
    (save-excursion
      (re-search-forward "^URL:\\( \\|\n\\)")
      (let ((url (buffer-substring-no-properties (point) (line-end-position))))
	;; alternative to eww readable view:
	;; (start-process "firefox" nil "firefox"
	;;                "-new-window"
	;;                (concat "about:reader?url=" url))
	(spw/next-eww-readable)
	(eww url)))))

(defvar spw/lists-browse-searches nil
  "Internal cache variable.")
(defvar spw/readall nil
  "Internal cache variable.")

(defun spw/notmuch-query-has-results-p (query)
  "Predicate testing whether any messages match notmuch query QUERY."
  (length> (process-lines notmuch-command
			  "search"
			  "--output=messages"
			  "--limit=1"
			  "--format=text"
			  "--format-version=4"
			  query)
	   0))

(cl-flet* ((connective (word)
                       (apply-partially
                        (lambda (connec &rest queries)
                          (mapconcat (lambda (query) (concat "(" query ")"))
				     (flatten-tree queries)
                                     (concat " " connec " ")))
                        word))
           (disjoin (connective "or"))
           (conjoin (connective "and"))
           (negate (query) (concat "not (" query ")"))
           (thread (query) (concat "thread:{" query "}")))
  (defvar spw/weekday-only-mail (disjoin "to:spwhitton@email.arizona.edu"
                                         "from:arizona.edu"
                                         (thread "tag:spw::work"))
    "Mail to be filtered out of processing views at the weekend.")

  (defun spw/standard-notmuch-saved-searches ()
    (interactive)
    (setq notmuch-saved-searches nil
          spw/lists-browse-searches nil)
    (when (file-exists-p (locate-user-emacs-file "notmuch-groups.el"))
      (load (locate-user-emacs-file "notmuch-groups"))
      (dolist (group spw/lists-browse)
        (let ((search
               (if (atom group)
                   ;; assume we got a List: search and extract the first
                   ;; component of the List-Id to use as the name of the
                   ;; search
                   (let ((name (if (string-match ":\\([^.]+\\)\\." group)
                                   (match-string 1 group)
                                 (error "Could not extract a list name"))))
                     `(:name ,name :search-type nil :sort-order newest-first
                             :query ,group))
                 ;; assume a plist and copy properties across
                 (let ((name (plist-get group :name))
                       (key (plist-get group :key))
                       (query (disjoin (plist-get group :queries))))
                   `(:name ,name :search-type nil :sort-order newest-first
                           :key ,key :query ,query)))))
          (add-to-list 'notmuch-saved-searches search t)
	  ;; also add the tag:unread version of the search as a saved search
	  ;; so that buffers created by `spw/next-unread-group' get a
	  ;; reasonable name
	  (let ((keyless-search (copy-sequence search)))
	    (plist-put keyless-search :key nil)
	    (plist-put keyless-search
		       :name
		       (concat (plist-get search :name) " unread"))
	    (plist-put keyless-search
		       :query
		       (conjoin "tag:unread" (plist-get search :query)))
	    (add-to-list 'notmuch-saved-searches keyless-search t))
          (add-to-list 'spw/lists-browse-searches
                       (cons (plist-get search :name)
                             (conjoin "tag:unread" (plist-get search :query)))
                       t))))

    (setq spw/readall
          (conjoin
           (disjoin
            "folder:inbox"

            ;; can use this to include all mail addressed directly
            ;; to me in processing views, as an alternative to
            ;; relying on 'folder:inbox'
            ;; (mapcar (lambda (a) (concat "to:" a)) (notmuch-user-emails))

            spw/lists-readall)
           (negate (thread "tag:spw::browse"))))

    ;; now prepend views for processing the day's mail addressed to me
    (let* ((to-process (conjoin "tag:unread" spw/readall))
           (to-process-weekend (conjoin to-process
                                        (negate spw/weekday-only-mail))))
      (add-to-list 'notmuch-saved-searches
                   `(:name "weekend unread" :key "w" :search-type nil
                           :sort-order oldest-first
                           :query ,to-process-weekend))
      (add-to-list 'notmuch-saved-searches
                   `(:name "weekday unread" :key "u" :search-type nil
                           :sort-order oldest-first
                           :query ,to-process)))

    ;; append some miscellaneous views
    (add-to-list 'notmuch-saved-searches
                 '(:name "flagged" :key "f" :search-type tree
                         :query "tag:flagged" ) t)
    (add-to-list 'notmuch-saved-searches
                 `(:name "sent" :key "s" :search-type nil
                         :sort-order newest-first
                         :query ,(disjoin
                                  (mapcar
                                   (lambda (a) (concat "from:" a))
                                   (notmuch-user-emails))))
                 t)
    (add-to-list 'notmuch-saved-searches
                 '(:name "drafts" :key "D" :search-type nil
                         :sort-order newest-first
                         :query "tag:draft") t)
    (add-to-list 'notmuch-saved-searches
                 '(:name "imported series" :key "P" :search-type nil
                         :sort-order newest-first
                         :query "subject:\"/PATCH .+ imported/\"") t)
    (add-to-list 'notmuch-saved-searches
		 '(:name "phone notes" :key "N" :search-type nil
			 :sort-order newest-first
			 :query "folder:notes") t)

    (let* ((categorised (disjoin
                         spw/readall
                         (mapcar (lambda (search)
                                   (if (atom search)
                                       search
                                     (plist-get search :queries)))
                                 spw/lists-browse)
                         spw/lists-archiveonly))
	   ;; content not from mailing lists and not otherwise categorised --
	   ;; previously such items would fall into "uncategorised unread" but
	   ;; that's wrong because I've explicitly subscribed to each of these
	   (uncategorised-feeds (conjoin "tag:unread"
					 "from:rss@spwhitton.name"
					 (negate categorised)))
	   ;; finally, groups/lists where I don't know how or whether I want
	   ;; to follow them; I may have subscribed just to post something
	   (uncategorised-other (conjoin "tag:unread"
					 (negate "from:rss@spwhitton.name")
					 (negate categorised)))
	   (feeds-query `(:name "uncategorised feeds"
				:key "R" :search-type nil
				:sort-order newest-first
				:query ,uncategorised-feeds))
	   (other-query `(:name "uncategorised unread"
				:key "U" :search-type nil
				:sort-order newest-first
				:query ,uncategorised-other)))
      ;; splice it in just after "weekday unread" and "weekend unread"
      (setcdr (cdr notmuch-saved-searches)
	      (cons (cons "uncategorised feeds" uncategorised-feeds)
		    (cddr notmuch-saved-searches)))
      (add-to-list 'notmuch-saved-searches other-query t)
      (add-to-list 'spw/lists-browse-searches
                   (cons "uncategorised feeds" uncategorised-feeds))
      (add-to-list 'spw/lists-browse-searches
                   (cons "uncategorised unread" uncategorised-other)
		   t)))

  (defun spw/notmuch-catchup-by-archive ()
    (interactive)
    (when (and (memq major-mode '(notmuch-tree-mode notmuch-search-mode))
	       (y-or-n-p "Are you sure you want to mark all as read?")
	       spw/readall)
      (let ((query (if (eq major-mode 'notmuch-tree-mode)
		       (notmuch-tree-get-query)
		     (notmuch-search-get-query))))
	(notmuch-tag (conjoin query (negate spw/readall)) '("-unread")))
      (spw/next-unread-group)))

  (defun spw/notmuch-catchup-by-killing ()
    (interactive)
    (when (and (eq major-mode 'notmuch-search-mode)
	       (y-or-n-p "Are you sure you want to kill all threads?")
	       spw/readall)
      (cl-loop initially (goto-char (point-min))
               for r = (notmuch-search-get-result)
                 then (and (notmuch-search-next-thread)
                           (notmuch-search-get-result))
               for ids = (car (plist-get r :query))
               while r
               if (and ;; Don't touch if any messages in the thread match
                       ;; `spw/readall' as we don't catchup such threads
                       (not (spw/notmuch-query-has-results-p
                             (conjoin (concat "thread:" (plist-get r :thread))
                                      spw/readall)))
                       ;; Don't touch unless there are unread messages, so
                       ;; that we skip over threads which have been manually
                       ;; processed -- this is in case I just archived the
                       ;; thread without killing it, and want any new messages
                       ;; to show up as unread.
                       ;;
                       ;; We can't rely on (plist-get r :tags) here because
                       ;; that might be out-of-date if the thread was archived
                       ;; from `notmuch-show-mode' rather than this buffer,
                       ;; and we can't refresh the buffer as we don't want to
                       ;; kill any newly-arrived threads
                       (spw/notmuch-query-has-results-p
                        (conjoin "tag:unread" ids)))
               do ;; Only catchup the messages that were part of this saved
		  ;; search
		  (notmuch-tag ids '("-unread"))
                  ;; As in `spw/kill-thread' for `notmuch-search-mode', want
                  ;; to tag only single messages with spw::killed
                  (notmuch-tag (car (split-string ids)) '("+spw::killed"))
	       finally (spw/next-unread-group))))

  (defun spw/notmuch-show-advance-and-archive ()
    "Like `notmuch-show-advance-and-archive' but confirm thread archive.

Note that this does not archive individual messages are you
scroll through them."
    (interactive)
    (when (or ;; since we have a confirmation, it's fine to archive when point
	      ;; it not yet at the bottom of the window
	      (pos-visible-in-window-p (point-max))
	      (notmuch-show-advance))
      (if (let ((map (make-sparse-keymap)))
	    (set-keymap-parent map query-replace-map)
	    (define-key map " " 'ignore)
	    ;; override usual map so SPC cannot confirm the archive, to avoid
	    ;; accidental archives
	    (let ((query-replace-map map))
	      (y-or-n-p "Mark all as read before moving on?")))
	  (when (and notmuch-show-thread-id notmuch-archive-tags)
	    ;; only tag messages which would have been expanded when we opened
	    ;; the thread
	    (notmuch-tag
	     (conjoin notmuch-show-query-context notmuch-show-thread-id)
	     (notmuch-tag-change-list notmuch-archive-tags nil))
	    (notmuch-show-next-thread t))
	(notmuch-show-next-thread-show)))))

;; use on views produced by `spw/next-unread-group'
(defun spw/notmuch-catchup (arg)
  (interactive "P")
  (if arg
      (spw/notmuch-catchup-by-archive)
    (spw/notmuch-catchup-by-killing))
  (message "Group caught up"))

(defun spw/next-unread-group ()
  (interactive)
  (let ((already-looking (boundp 'spw/more-unread-groups))
        (queries (bound-and-true-p spw/more-unread-groups))
        (remaining))
    (when already-looking
      (when (eq major-mode 'notmuch-tree-mode)
	(notmuch-tree-close-message-window))
      (kill-buffer (current-buffer)))
    (if (or (and already-looking (not queries))
            (not (setq remaining (seq-drop-while
                                  (lambda (q)
                                    (zerop (string-to-number
                                            (notmuch-saved-search-count
                                             (cdr q)))))
                                  (or queries spw/lists-browse-searches)))))
        (notmuch-hello)
      ;; I think that a tree-style view is probably best for browsing groups,
      ;; but atm notmuch-tree's use of windows is a bit inflexible, so use
      ;; notmuch-search
      ;; (notmuch-tree (cdar remaining) nil nil
      ;;               (concat "*notmuch-tree-saved-search-"
      ;;                       (caar remaining) "*"))
      (notmuch-search (cdar remaining) t)
      ;; renaming the buffer seems to break refreshing it & reversing the
      ;; sort order
      ;; (rename-buffer (concat "*notmuch-saved-search-" (caar remaining) "*") t)
      (set (make-local-variable 'spw/more-unread-groups)
           (cdr remaining))
      (put 'spw/more-unread-groups 'permanent-local t))))

(defun spw/notmuch-mua-send-and-exit ()
  (interactive)
  (when (or spw/message-normalised
	    (y-or-n-p "Send message which has not been auto-formatted?"))
    (call-interactively #'notmuch-mua-send-and-exit)))


;; In a thread with patches, try to collapse messages not relevant for
;; reviewing those patches.  Optional numeric prefix argument specifies the
;; version of the series to review, in case there is more than one series in
;; the thread.  Include spw::unresolved mail, as these may contain unresolved
;; review comments on older versions of the series.
;;
;; In the case where you want to compare the new series against unresolved
;; review comments on the old series, and the series are in different threads,
;; open each thread in a separate buffer (probably in separate frames).  Run
;; this command in the new series' buffer and hit `l tag:spw::unresolved RET'
;; in the old series' buffer
(defun spw/notmuch-show-filter-thread-patches (&optional reroll-count)
  (interactive "P")
  (let ((subject-filter
         (if reroll-count
             (let ((n (prefix-numeric-value reroll-count)))
               (if (= n 1)
		   (concat "("
			   "subject:/\\[.*PATCH[^v]*\\]/"
			   "or"
			   "subject:/\\[.*PATCH.*v1.*\\]/"
			   ")")
                 (concat "subject:/\\[.*PATCH.*v"
			 (number-to-string n)
			 ".*\\]/")))
           "subject:/\\[.*PATCH.*\\]/ ")))
    (notmuch-show-filter-thread
     (concat "tag:unread or tag:spw::unresolved or ("
             subject-filter
             " and not subject:'Re:' and not subject:'Info received')"))))

(defun spw/notmuch-show-with-remote-images ()
  (interactive)
  (setq-local notmuch-show-text/html-blocked-images nil
	      notmuch-multipart/alternative-discouraged '("text/plain"))
  (notmuch-show-refresh-view))


;;;; Startup

(unless spw/lists-browse-searches
  (spw/standard-notmuch-saved-searches))

;;; init-notmuch.el ends here