X-Git-Url: https://git.cworth.org/git?p=notmuch-wiki;a=blobdiff_plain;f=emacstips.mdwn;h=58641771798bd3f61bb34bd8b6bf7613f4f8fb77;hp=2ce59e76dcdb0544341d87a23225a029aefe08c6;hb=HEAD;hpb=d8bb8bb5af6c1ecabf3fc3b702c4491fea31f4bf diff --git a/emacstips.mdwn b/emacstips.mdwn index 2ce59e7..288690c 100644 --- a/emacstips.mdwn +++ b/emacstips.mdwn @@ -6,19 +6,7 @@ Emacs Interface|notmuch-emacs]] page for basics. [[!toc levels=2]] -## Issues with Emacs 24 - -If notmuch-show-mode behaves badly for you in emacs 24.x try adding one of - - (setq gnus-inhibit-images nil) - -or - - (require 'gnus-art) - -to your .emacs file. - -## Controlling external handlers for attachements +## Controlling external handlers for attachments You can choose e.g. which pdf viewer to invoke from notmuch-show mode by adding a .mailcap file in your home directory. Here is an example: @@ -26,6 +14,53 @@ adding a .mailcap file in your home directory. Here is an example: application/pdf; /usr/bin/mupdf %s; test=test "$DISPLAY" != ""; description=Portable Document Format; nametemplate=%s.pdf application/x-pdf; /usr/bin/mupdf %s; test=test "$DISPLAY" != ""; description=Portable Document Format; nametemplate=%s.pdf +### Convert ".pdf" and ".docx" to text and pop to buffer + +Add the following (hacky but effective!) code to `.emacs.d/notmuch-config.el`; +the overwritten `defcustom` will change action when pressing RET on top of an +attachment; ".pdf" and ".docx" attachments are converted to text (using +"pdf2text" and "docx2txt.pl" commands to do the conversion), saving to file +(the default action of `notmuch-show-part-button-default-action`) is offered +to attachments of other types. + + (defun user/mm-pipe-- (handle cmd) + ;; conveniently, '-' '-' a args to pdftotext and docx2txt.pl work fine + ;; fixme: naming inconsistency (fn name and buffer name) + (let ((buffer (get-buffer-create "*attachment-to-text*"))) + (with-current-buffer buffer + (setq buffer-read-only nil) + (erase-buffer)) + (with-temp-buffer + ;; "based on mm-pipe-part in mm-decode.el" + (mm-with-unibyte-buffer + (mm-insert-part handle) + (mm-add-meta-html-tag handle) + (let ((coding-system-for-write 'binary)) + (call-process-region (point-min) (point-max) + cmd nil buffer nil "-" "-")))) + (pop-to-buffer buffer) + (goto-char (point-min)) + (text-mode) + (visual-line-mode) + (view-mode))) + + (defun user/notmuch-show-pop-attachment-to-buffer () + ;; "based on notmuch-show-apply-to-current-part-handle" + (interactive) + (let ((handle (notmuch-show-current-part-handle))) + ;;(message "%s" handle) + (unwind-protect + (pcase (car (nth 1 handle)) + ("application/pdf" + (user/mm-pipe-- handle "pdftotext")) + ("application/vnd.openxmlformats-officedocument.wordprocessingml.document" + (user/mm-pipe-- handle "docx2txt.pl")) + (_ (notmuch-show-save-part))) + (kill-buffer (mm-handle-buffer handle))))) + + (setq notmuch-show-part-button-default-action + #'user/notmuch-show-pop-attachment-to-buffer) + ## Overwriting the sender address If you want to always use the same sender address, then the following @@ -94,7 +129,7 @@ above. To get this behaviour on 0.17+ do the following: (define-key notmuch-search-mode-map "S" (lambda (&optional beg end) "mark thread as spam" - (interactive (notmuch-search-interactive-region)) + (interactive (notmuch-interactive-region)) (notmuch-search-tag (list "+spam" "-inbox") beg end))) The analogous functionality in notmuch-tree is currently missing. @@ -156,11 +191,15 @@ reply-to-all. Here's how to swap the reply to sender/all bindings in show mode: (define-key notmuch-show-mode-map "r" 'notmuch-show-reply) (define-key notmuch-show-mode-map "R" 'notmuch-show-reply-sender) -And in search mode: +In search mode: (define-key notmuch-search-mode-map "r" 'notmuch-search-reply-to-thread) (define-key notmuch-search-mode-map "R" 'notmuch-search-reply-to-thread-sender) +And in tree mode: + + (define-key notmuch-tree-mode-map "r" (notmuch-tree-close-message-pane-and #'notmuch-show-reply)) + (define-key notmuch-tree-mode-map "R" (notmuch-tree-close-message-pane-and #'notmuch-show-reply-sender)) ## How to do FCC/BCC... @@ -189,6 +228,11 @@ address. Please see the documentation for the variable `notmuch-fcc-dirs` in the customization window for how to arrange this. +The `notmuch-fcc-dirs` variable is only taken into account when mails +are composed using `notmuch-mua-mail`. If you want to use the notmuch +mail user agent by default, the `mail-user-agent` needs to be +customized to use the `notmuch-user-agent`. + ## How to customize `notmuch-saved-searches` When starting notmuch, a list of saved searches and message counts is @@ -245,6 +289,21 @@ Sometimes it may be necessary to display the message, or a single MIME part, in an external browser. This can be done by `(notmuch-show-view-part)`, bound to `. v` by default. +This command will try to view the message part the point is on with an +external viewer. The mime-type of the part will determine what viewer +will be used. Typically a 'text/html' part will be send to your +browser. + +The configuration for this is kept in so called `mailcap` +files. (typically the file is `~/.mailcap` or `/etc/mailcap`) If the +wrong viewer is started or something else goes wrong, there's a good +chance something needs to be adapted in the mailcap configuration. + +For Example: The `copiousoutput` setting in mailcap files needs to be +removed for some mime-types to prevent immediate removal of temporary +files so the configured viewer can access them. + + ## msmtp, message mode and multiple accounts As an alternative to running a mail server such as sendmail or postfix @@ -335,7 +394,7 @@ If you are not yet running 0.22, you can still use it by adding a wrapper around the command called, say, `notmuch-address`: #!/bin/sh - exec notmuch address from:"$@" + exec notmuch address from:"$*" Then you can set the `notmuch-address-command` to `notmuch-address` (if it is in your `$PATH` of course, otherwise use an absolute path). @@ -372,7 +431,7 @@ available: cc -o addrlookup addrlookup.c `pkg-config --cflags --libs gobject-2.0` -lnotmuch * Shell/fgrep/perl combination [nottoomuch-addresses.sh](https://github.com/domo141/nottoomuch/blob/master/nottoomuch-addresses.rst). - This tools maintains it's own address "database" gathered from email + This tools maintains its own address "database" gathered from email files notmuch knows and search from that "database" is done by `fgrep(1)`. * python/sqlite combination [notmuch-abook](https://github.com/guyzmo/notmuch-abook/) @@ -437,11 +496,20 @@ address. ## How to sign/encrypt messages with gpg -Messages can by signed using gpg by invoking +Messages can be signed using gpg by invoking `M-x mml-secure-sign-pgpmime` (or `M-x mml-secure-encrypt-pgpmime`). These functions are available via the standard `message-mode` keybindings -`C-c C-m s p` and `C-c C-m c p`. To sign outgoing mail by default, use the -`message-setup-hook` in your `.emacs` file: +`C-c C-m s p` and `C-c C-m c p`. + +In Emacs 28 you will be asked whether to sign the message using the +sender and are offered to remember your choice. In Emacs 27 you will +get a slightly misleading error and have to manually add the following +line to you init file. Older Emacsen just do this unconditionally. + + (setq mml-secure-openpgp-sign-with-sender t) + +To sign outgoing mail by default, use the `message-setup-hook` in your +init file: ;; Sign messages by default. (add-hook 'message-setup-hook 'mml-secure-sign-pgpmime) @@ -455,6 +523,42 @@ Alternatively, you may prefer to use `mml-secure-message-sign-pgpmime` instead of `mml-secure-sign-pgpmime` to sign the whole message instead of just one part. +If you want to automatically encrypt outgoing messages if the keyring +contains a public key for every recipient, you can add something like +that to your `.emacs` file: + + (defun message-recipients () + "Return a list of all recipients in the message, looking at TO, CC and BCC. + + Each recipient is in the format of `mail-extract-address-components'." + (mapcan (lambda (header) + (let ((header-value (message-fetch-field header))) + (and + header-value + (mail-extract-address-components header-value t)))) + '("To" "Cc" "Bcc"))) + + (defun message-all-epg-keys-available-p () + "Return non-nil if the pgp keyring has a public key for each recipient." + (require 'epa) + (let ((context (epg-make-context epa-protocol))) + (catch 'break + (dolist (recipient (message-recipients)) + (let ((recipient-email (cadr recipient))) + (when (and recipient-email (not (epg-list-keys context recipient-email))) + (throw 'break nil)))) + t))) + + (defun message-sign-encrypt-if-all-keys-available () + "Add MML tag to encrypt message when there is a key for each recipient. + + Consider adding this function to `message-send-hook' to + systematically send encrypted emails when possible." + (when (message-all-epg-keys-available-p) + (mml-secure-message-sign-encrypt))) + + (add-hook 'message-send-hook #'message-sign-encrypt-if-all-keys-available + ### Troubleshooting message-mode gpg support - If you have trouble with expired subkeys, you may have encountered @@ -472,11 +576,17 @@ Encrypted and signed mime messages can be read and verified with: (setq notmuch-crypto-process-mime t) -Decrypting or verifying inline pgp messages can be done by selecting -an the inline pgp area and and using: +Decrypting inline pgp messages can be done by selecting an the inline pgp area +and using: M-x epa-decrypt-region RET +Verifying of inline pgp messages is not supported directly ([reasons +here](https://dkg.fifthhorseman.net/notes/inline-pgp-harmful/)). You can still +verify a part using + + M-x notmuch-show-pipe-part RET gpg --verify RET + ## Multiple identities using gnus-alias [gnus-alias](http://www.emacswiki.org/emacs/GnusAlias) allows you to @@ -522,8 +632,8 @@ Here is an example configuration. ;; Use "home" identity by default (setq gnus-alias-default-identity "home") ;; Define rules to match work identity - (setq gnus-alias-identity-rules) - '(("work" ("any" "john.doe@\\(example\\.com\\|help\\.example.com\\)" both) "work")) + (setq gnus-alias-identity-rules + '(("work" ("any" "john.doe@\\(example\\.com\\|help\\.example.com\\)" both) "work"))) ;; Determine identity when message-mode loads (add-hook 'message-setup-hook 'gnus-alias-determine-identity) @@ -544,6 +654,17 @@ The last two do the same thing. See also the **Usage:** section in `gnus-alias.el`. +## Multiple identities (and more) with message-templ + +Another option for multiple identities is +[message-templ](http://git.tethera.net/message-templ.git) +(also a available in marmalade). This provides roughly the same +facilities as wanderlust's template facility. + +See +[example.emacs.el](https://git.tethera.net/message-templ.git/tree/example.emacs.el) +for some simple examples of usage. + ## Resending (or bouncing) messages Add the following to your [notmuch init file](/notmuch-emacs#notmuch_init_file) to be able @@ -600,8 +721,7 @@ tabs with spaces in subject lines: (add-hook 'notmuch-show-markup-headers-hook 'notmuch-show-subject-tabs-to-spaces) -And in header lines (this will only work with the yet to be released -notmuch version 0.15): +And in header lines: (defun notmuch-show-header-tabs-to-spaces () "Replace tabs with spaces in header line." @@ -617,7 +737,7 @@ I like to have an inbox saved search, but only show unread messages when they view a thread. This takes two steps: 1. Apply -[this patch from Mark Walters](http://notmuchmail.org/pipermail/notmuch/2012/010817.html) +[this patch from Mark Walters](https://notmuchmail.org/pipermail/notmuch/2012/010817.html) to add the `notmuch-show-filter-thread` function. 1. Add the following hook to your emacs configuration: @@ -671,13 +791,33 @@ In Debian and derivatives, (add-to-list 'load-path "/usr/share/org-mode/lisp") +In NixOS, using `emacsWithPackages (epkgs: [ epkgs.orgPackages.org-plus-contrib ])`, + + (loop for p in load-path + do (if (file-accessible-directory-p p) + (let ((m (directory-files-recursively p "^ol-notmuch.el$"))) + (if m (add-to-list 'load-path (file-name-directory (car m))))))) + Then - (require 'org-notmuch) + (require 'ol-notmuch) In general it is nice to have a key for org-links (not just for notmuch). For example - (define-key global-map "\C-cl" 'org-store-link) + (define-key global-map "\C-c l" 'org-store-link) + +If you're using `use-package` the package can be loaded using the following: + +```emacs-lisp +(use-package ol-notmuch + :ensure t + :bind + ("C-c l" . org-store-link)) +``` + +Note the package was renamed from `org-notmuch` to `ol-notmuch` in recent +versions of org-mode. If you're using an old version of notmuch you might want +to `(require 'org-notmuch)` instead. ## Viewing diffs in notmuch @@ -689,25 +829,27 @@ refine, next hunk etc all work. "View the the current message as a patch." (interactive) (let* ((id (notmuch-show-get-message-id)) + (msg (notmuch-show-get-message-properties)) + (part (notmuch-show-get-part-properties)) (subject (concat "Subject: " (notmuch-show-get-subject) "\n")) (diff-default-read-only t) (buf (get-buffer-create (concat "*notmuch-patch-" id "*"))) (map (make-sparse-keymap))) - (define-key map "q" 'notmuch-kill-this-buffer) + (define-key map "q" 'notmuch-bury-or-kill-this-buffer) (switch-to-buffer buf) (let ((inhibit-read-only t)) (erase-buffer) (insert subject) - (insert (notmuch-get-bodypart-internal id 1 nil))) + (insert (notmuch-get-bodypart-text msg part nil))) (set-buffer-modified-p nil) (diff-mode) (lexical-let ((new-ro-bind (cons 'buffer-read-only map))) (add-to-list 'minor-mode-overriding-map-alist new-ro-bind)) (goto-char (point-min)))) -and then this function needs to bound into the keymap with something like +and then this function needs to bound to `. d` in the keymap - (define-key 'notmuch-show-mode-map "D" 'my-notmuch-show-view-as-patch) + (define-key 'notmuch-show-part-map "d" 'my-notmuch-show-view-as-patch) ## Interfacing with Patchwork @@ -745,7 +887,7 @@ Add a new entry with "Function returning the URL:" set to: "-f" "%{id}")))) Replacing `http://patchwork.example.com/patch/`, `/path/to/pwclient`, and -`the-project` appropiately. You should now be able to stash the Patchwork URL +`the-project` appropriately. You should now be able to stash the Patchwork URL using `c l`. Going further, if the patch has been committed, you can get the commit hash with @@ -770,3 +912,117 @@ can turn the commit hash into a URL pointing there, for example: "-m" (concat "<" message-id ">") "-n" "1" "-f" "%{commit_ref}")))) + +## Never forget attachments + +Very often we forget to actually attach the file when we send an email +that's supposed to have an attachment. Did this never happen to you? +If not, then it will. + +Since version 0.29 Notmuch includes the `notmuch-mua-attachment-check` +function. This function checks whether a message references an +attachment and if it finds none it asks for confirmation before +sending the message. The function is meant to be added to the +`message-send-hook`, like so: + + (add-hook 'message-send-hook 'notmuch-mua-attachment-check) + +The "customize"able variable `notmuch-mua-attachment-regexp` controls +how reference to an attachment are identified. By default, it +identifies English and French terms. For example, the following makes +it recognise English and Portuguese terms: + + (setq-default notmuch-mua-attachment-regexp + "\\b\\(attach\\|attachment\\|attached\\|anexo\\|anexado\\)\\b") + + +## Avoid forgetting the subject + +It happens that we forget to enter the Subject line, particularly when +we leave that to the end. It's easy to write a function that checks +whether the Subject is empty, and add it to `message-send-hook` to get +confirmation: + + (defun my-notmuch-mua-empty-subject-check () + "Request confirmation before sending a message with empty subject" + (when (and (null (message-field-value "Subject")) + (not (y-or-n-p "Subject is empty, send anyway? "))) + (error "Sending message cancelled: empty subject."))) + (add-hook 'message-send-hook 'my-notmuch-mua-empty-subject-check) + + +## Applying patches to git repositories + +The `notmuch-extract-thread-patches` and +`notmuch-extract-message-patches` commands from the `elpa-mailscripts` +package in Debian (and its derivatives) can do this for you. + +## Allow content preference based on message context + +The preference for which sub-part of a multipart/alternative part is shown is +globally set. For example, if you prefer showing the html version over the text +based, you can set: + + (setq notmuch-multipart/alternative-discouraged '("text/plain" "text/html")) + +However, sometimes you might want to adapt your preference depending on the +context. You can override the default settings on a per-message basis by +providing a function that has access to the message and which returns the +discouraged type list. For example: + + (defun my/determine-discouraged (msg) + (let* ((headers (plist-get msg :headers)) + (from (or (plist-get headers :From) ""))) + (cond + ((string-match "whatever@mail.address.com" from) + '("text/plain")) + (t + '("text/html" "multipart/related"))))) + + (setq notmuch-multipart/alternative-discouraged + 'my/determine-discouraged) + +This would discourage text/html and multipart/related generally, but discourage +text/plain should the message be sent from whatever@mail.address.com. + +## See the recipient address instead of your address when listing sent messages + +If you like to see your sent messages in unthreaded view, by default you will +see your address in the authors column, which is maybe not what you want. The +following code allows for showing the recipients if your email address (an +arbitrary address, whatever@mail.address.com in the example) is included in the +From field. + + (defun my/notmuch-unthreaded-show-recipient-if-sent (format-string result) + (let* ((headers (plist-get result :headers)) + (to (plist-get headers :To)) + (author (plist-get headers :From)) + (face (if (plist-get result :match) + 'notmuch-tree-match-author-face + 'notmuch-tree-no-match-author-face))) + (propertize + (format format-string + (if (string-match "whatever@mail.address.com" author) + (concat "↦ " (notmuch-tree-clean-address to)) + (notmuch-tree-clean-address to) + author)) + 'face face))) + + (setq notmuch-unthreaded-result-format + '(("date" . "%12s ") + (my/notmuch-unthreaded-show-recipient-if-sent . "%-20.20s") + ((("subject" . "%s")) + . " %-54s ") + ("tags" . "(%s)"))) + +## Issues with Emacs 24 (unsupported since notmuch 0.31 (2020-09-05)) + +If notmuch-show-mode behaves badly for you in emacs 24.x try adding one of + + (setq gnus-inhibit-images nil) + +or + + (require 'gnus-art) + +to your .emacs file.