Start fresh with a new mu4e config

This commit is contained in:
Jeremy Dormitzer 2020-04-20 10:34:10 -04:00
parent fb981f0f16
commit bb9fa4e621
2 changed files with 65 additions and 336 deletions

View File

@ -3610,336 +3610,76 @@ For some reason Emacs is starting up with the dashboard and the *scratch* buffer
(delete-other-windows)))
#+END_SRC
* Mu4e
Because email in Emacs is badass. My mail set up is based on [[http://stevelosh.com/blog/2012/10/the-homely-mutt/][this mutt setup]] and [[https://notanumber.io/2016-10-03/better-email-with-mu4e/][this mu4e setup]].
#+BEGIN_SRC emacs-lisp
(defvar jdormit/mu4e-load-path
(if (file-exists-p "/usr/local/share/emacs/site-lisp/mu/mu4e")
"/usr/local/share/emacs/site-lisp/mu/mu4e"
(if (file-exists-p "/usr/share/emacs/site-lisp/mu4e")
"/usr/share/emacs/site-lisp/mu4e")))
* Email
I use [[https://www.djcbsoftware.nl/code/mu/mu4e.html][mu/mu4e]] as my email client.
(add-to-list 'load-path jdormit/mu4e-load-path)
(autoload 'mu4e (concat jdormit/mu4e-load-path "/mu4e.el"))
(autoload 'mu4e-update-index (concat jdormit/mu4e-load-path "/mu4e.el"))
First, add it to the load path:
#+BEGIN_SRC emacs-lisp
(defvar mu4e-load-path
(cond
((file-exists-p "/usr/local/share/emacs/site-lisp/mu/mu4e")
"/usr/local/share/emacs/site-lisp/mu/mu4e")
((file-exists-p "/usr/share/emacs/site-lisp/mu4e")
"/usr/local/share/emacs/site-lisp/mu4e")))
(add-to-list 'load-path mu4e-load-path)
#+END_SRC
Then set up autoloads on the entry functions:
#+BEGIN_SRC emacs-lisp
(autoload 'mu4e (concat mu4e-load-path "/mu4e.el"))
(autoload 'mu4e (concat mu4e-load-path "/mu4e.el"))
#+END_SRC
Then configure it:
#+begin_src emacs-lisp
(with-eval-after-load 'mu4e
(require 'org-mu4e)
(setq
;; General
mu4e-maildir (expand-file-name "~/.mail")
message-send-mail-function 'message-send-mail-with-sendmail
mu4e-get-mail-command "mbsync -a"
mu4e-completing-read-function 'completing-read
mu4e-attachment-dir (expand-file-name "~/Downloads")
;; Getting mail
mu4e-get-mail-command "mbsync -a"
;; Sending mail
mu4e-send-mail-function 'message-send-mail-with-sendmail
sendmail-program (executable-find "msmtp")
mu4e-attachment-dir "~/Downloads"
mu4e-compose-format-flowed t
mu4e-html2text-command "w3m -dump -T text/html -o display_link_number=1"
mu4e-change-filenames-when-moving t
org-mu4e-link-query-in-headers-mode nil
mu4e-maildirs-extension-custom-list
'("/jeremy-dormitzer-gmail-com/Inbox"
"/jeremy-getpterotype-com/Inbox")
;; Let Gmail handle putting sent messages in the sent folder
mu4e-sent-messages-behavior 'delete
;; Make sure mu4e knows about my different accounts
mu4e-context-policy 'ask
mu4e-compose-context-policy 'ask
mu4e-contexts
(let ((per-dir "/jeremy-dormitzer-gmail-com")
(pterotype-dir "/jeremy-getpterotype-com")
(lola-dir "/jeremydormitzer-lola-com"))
`(,(make-mu4e-context
:name "Pterotype"
:name "Personal Gmail"
:match-func (lambda (msg)
(when msg ())
(when msg (string-match-p
"jeremy-getpterotype-com"
(mu4e-message-field msg :path))))
:vars `((user-mail-address . "jeremy@getpterotype.com")
(user-full-name . "Jeremy Dormitzer")
(mu4e-sent-folder . ,(concat pterotype-dir "/Sent"))
(mu4e-drafts-folder . ,(concat pterotype-dir "/Drafts"))
(mu4e-refile-folder . ,(concat pterotype-dir "/Archive"))
(mu4e-trash-folder . ,(concat pterotype-dir "/Trash"))
(mu4e-sent-messages-behavior . delete)
(mu4e-get-mail-command . "mbsync jeremy-getpterotype-com")
(message-sendmail-extra-arguments
. ("-a" "jeremy-getpterotype.com"))))
,(make-mu4e-context
:name "GMail"
:match-func (lambda (msg)
(when msg (string-match-p
(when msg
(string-match-p
"jeremy-dormitzer-gmail-com"
(mu4e-message-field msg :path))))
:vars `((user-mail-address . "jeremy.dormitzer@gmail.com")
(user-full-name . "Jeremy Dormitzer")
(mu4e-sent-folder . ,(concat per-dir "/Sent"))
(mu4e-drafts-folder . ,(concat per-dir "/Drafts"))
(mu4e-refile-folder . ,(concat per-dir "/Archive"))
(mu4e-trash-folder . ,(concat per-dir "/Trash"))
(mu4e-sent-messages-behavior . delete)
:vars '((user-email-address . "jeremy.dormitzer@gmail.com")
(mu4e-sent-folder . "/jeremy-dormitzer-gmail-com/Sent")
(mu4e-drafts-folder . "/jeremy-dormitzer-gmail-com/Drafts")
(mu4e-refile-folder . "/jeremy-dormitzer-gmail-com/Archive")
(mu4e-trash-folder . "/jeremy-dormitzer-gmail-com/Trash")
(mu4e-get-mail-command . "mbsync jeremy-dormitzer-gmail-com")
(message-sendmail-extra-arguments
. ("-a" "jeremy.dormitzer-gmail.com"))))
. ("-a" "jeremy-dormitzer-gmail-com"))))
,(make-mu4e-context
:name "Lola"
:name "Lola Gmail"
:match-func (lambda (msg)
(when msg ())
(when msg (string-match-p
(when msg
(string-match-p
"jeremydormitzer-lola-com"
(mu4e-message-field msg :path))))
:vars `((user-mail-address . "jdormit@lola.com")
(user-full-name . "Jeremy Dormitzer")
(mu4e-sent-folder . ,(concat lola-dir "/Sent"))
(mu4e-drafts-folder . ,(concat lola-dir "/Drafts"))
(mu4e-refile-folder . ,(concat lola-dir "/Archive"))
(mu4e-trash-folder . ,(concat lola-dir "/Trash"))
(mu4e-sent-messages-behavior . delete)
:vars '((user-email-address . "jeremydormitzer@lola.com")
(mu4e-sent-folder . "/jeremydormitzer-lola-com/Sent")
(mu4e-drafts-folder . "/jeremydormitzer-lola-com/Drafts")
(mu4e-refile-folder . "/jeremydormitzer-lola-com/Archive")
(mu4e-trash-folder . "/jeremydormitzer-lola-com/Trash")
(mu4e-get-mail-command . "mbsync jeremydormitzer-lola-com")
(message-sendmail-extra-arguments
. ("-a" "jeremydormitzer-lola.com"))))))
mu4e-context-policy 'ask
mu4e-compose-context-policy 'ask-if-none))
(jdormit/define-prefix "am" "mu4e")
(leader-def-key "amm" 'mu4e)
#+END_SRC
Custom actions:
#+BEGIN_SRC emacs-lisp
(defun mu4e-view-go-to-url-w3m (&optional MULTI)
(let ((browse-url-browser-function 'w3m-browse-url))
(mu4e-view-go-to-url MULTI)))
(defun mu4e-action-view-in-browser-w3m (msg)
(let ((browse-url-browser-function 'w3m-browse-url))
(mu4e-action-view-in-browser msg)))
(with-eval-after-load 'mu4e
(add-to-list 'mu4e-view-actions
'("View in browser" . mu4e-action-view-in-browser) t)
(add-to-list 'mu4e-view-actions
'("WView in w3m" . mu4e-action-view-in-browser-w3m) t)
(add-to-list 'mu4e-view-actions
'("wGo to URL with w3m" . mu4e-view-go-to-url-w3m) t))
#+END_SRC
Make mu4e the default sendmail program:
#+BEGIN_SRC emacs-lisp
(setq mail-user-agent 'mu4e-user-agent)
#+END_SRC
Use the spacebar as a leader key in mu4e modes:
#+BEGIN_SRC emacs-lisp
(general-def mu4e-main-mode-map "SPC" leader-map)
(general-def mu4e-headers-mode-map "SPC" leader-map)
(general-def mu4e-view-mode-map "SPC" leader-map)
#+END_SRC
** HTML email
*** Redefinitions
Redefine =org-mime-insert-html-content= to export the plain part of HTML emails as ascii instead of org:
#+BEGIN_SRC emacs-lisp
(with-eval-after-load 'org-mime
(defun org-mime-insert-html-content (body file s opts)
(let* ((files (org-mime-extract-non-image-files))
;; dvipng for inline latex because MathJax doesn't work in mail
;; Also @see https://github.com/org-mime/org-mime/issues/16
;; (setq org-html-with-latex nil) sometimes useful
(org-html-with-latex org-mime-org-html-with-latex-default)
;; we don't want to convert org file links to html
(org-html-link-org-files-as-html nil)
(org-link-file-path-type 'absolute)
;; makes the replies with ">"s look nicer
(org-export-preserve-breaks org-mime-preserve-breaks)
(plain (org-mime--export-string body 'ascii))
;; org 9
(org-html-htmlize-output-type 'inline-css)
;; org 8
(org-export-htmlize-output-type 'inline-css)
(html-and-images (org-mime-replace-images (org-mime--export-string s 'html opts)
file))
(images (cdr html-and-images))
(html (org-mime-apply-html-hook (car html-and-images))))
;; If there are files that were attached, we should remove the links,
;; and mark them as attachments. The links don't work in the html file.
(when files
(mapc (lambda (f)
(setq html (replace-regexp-in-string
(format "<a href=\"%s\">%s</a>"
(regexp-quote f) (regexp-quote f))
(format "%s (attached)" (file-name-nondirectory f))
html)))
files))
(insert (org-mime-multipart plain
html
(mapconcat 'identity images "\n")))
;; Attach any residual files
(when files
(mapc (lambda (f)
(when org-mime-debug (message "attaching: %s" f))
(mml-attach-file f))
files)))))
#+END_SRC
And redefine =mu4e~compose-handler= to add a new hook:
#+BEGIN_SRC emacs-lisp
(defcustom jdormit-mu4e-compose-hook nil
"Hook run after the message composition buffer is set up"
:type 'hook
:group 'mu4e-compose)
(with-eval-after-load 'mu4e
(defun* mu4e~compose-handler (compose-type &optional original-msg includes)
"Create a new draft message, or open an existing one.
COMPOSE-TYPE determines the kind of message to compose and is a
symbol, either `reply', `forward', `edit', `resend' `new'. `edit'
is for editing existing (draft) messages. When COMPOSE-TYPE is
`reply' or `forward', MSG should be a message plist. If
COMPOSE-TYPE is `new', ORIGINAL-MSG should be nil.
Optionally (when forwarding, replying) ORIGINAL-MSG is the original
message we will forward / reply to.
Optionally (when forwarding) INCLUDES contains a list of
(:file-name <filename> :mime-type <mime-type> :disposition <disposition>)
for the attachements to include; file-name refers to
a file which our backend has conveniently saved for us (as a
tempfile)."
;; Run the hooks defined for `mu4e-compose-pre-hook'. If compose-type is
;; `reply', `forward' or `edit', `mu4e-compose-parent-message' points to the
;; message being forwarded or replied to, otherwise it is nil.
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
(put 'mu4e-compose-parent-message 'permanent-local t)
;; remember the compose-type
(set (make-local-variable 'mu4e-compose-type) compose-type)
(put 'mu4e-compose-type 'permanent-local t)
;; maybe switch the context
(mu4e~context-autoswitch mu4e-compose-parent-message
mu4e-compose-context-policy)
(run-hooks 'mu4e-compose-pre-hook)
;; this opens (or re-opens) a messages with all the basic headers set.
(let ((winconf (current-window-configuration)))
(condition-case nil
(mu4e-draft-open compose-type original-msg)
(quit (set-window-configuration winconf)
(mu4e-message "Operation aborted")
(return-from mu4e~compose-handler))))
;; insert mail-header-separator, which is needed by message mode to separate
;; headers and body. will be removed before saving to disk
(mu4e~draft-insert-mail-header-separator)
;; maybe encrypt/sign replies
(mu4e~compose-crypto-reply original-msg compose-type)
;; include files -- e.g. when forwarding a message with attachments,
;; we take those from the original.
(save-excursion
(goto-char (point-max)) ;; put attachments at the end
(dolist (att includes)
(mml-attach-file
(plist-get att :file-name) (plist-get att :mime-type))))
;; buffer is not user-modified yet
(mu4e~compose-set-friendly-buffer-name compose-type)
(set-buffer-modified-p nil)
;; now jump to some useful positions, and start writing that mail!
(if (member compose-type '(new forward))
(message-goto-to)
(message-goto-body))
;; bind to `mu4e-compose-parent-message' of compose buffer
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
(put 'mu4e-compose-parent-message 'permanent-local t)
;; hide some headers
(mu4e~compose-hide-headers)
;; switch on the mode
(mu4e-compose-mode)
(run-hooks 'jdormit-mu4e-compose-hook)
;; set mu4e-compose-type once more for this buffer,
;; we loose it after the mode-change, it seems
(set (make-local-variable 'mu4e-compose-type) compose-type)
(put 'mu4e-compose-type 'permanent-local t)
(when mu4e-compose-in-new-frame
;; make sure to close the frame when we're done with the message these are
;; all buffer-local;
(push 'delete-frame message-exit-actions)
(push 'delete-frame message-postpone-actions))))
#+END_SRC
*** Actual HTML mail logic
#+BEGIN_SRC emacs-lisp
(with-eval-after-load 'mu4e (require 'org-mu4e))
(use-package org-mime
:after (mu4e org)
:config
(setq org-mime-export-options '(:section-numbers nil
:with-author nil
:with-toc nil)))
(defun htmlize-and-send ()
(interactive)
(when (member 'org~mu4e-mime-switch-headers-or-body post-command-hook)
(org-mime-htmlize)
(message-send-and-exit)))
(add-hook 'org-ctrl-c-ctrl-c-hook #'htmlize-and-send t)
(defun setup-compose-buffer ()
(org-mu4e-compose-org-mode))
(add-hook 'jdormit-mu4e-compose-hook #'setup-compose-buffer)
#+END_SRC
When citing (quoting) messages in a reply, wrap them in org quote blocks instead of prefixing each line with '> ':
#+BEGIN_SRC emacs-lisp
(defun jdormit-citation-line-function ()
(message-insert-citation-line)
(insert "#+BEGIN_QUOTE\n"))
(defun jdormit-cite-function ()
(let ((message-yank-prefix "")
(message-yank-cited-prefix "")
(message-yank-empty-prefix ""))
(save-excursion
(message-cite-original)
(goto-char (point-max))
(insert "\n#+END_QUOTE"))))
(with-eval-after-load 'mu4e
(setq message-citation-line-function #'jdormit-citation-line-function
mu4e-compose-cite-function #'jdormit-cite-function))
#+END_SRC
Some keybindings to send the current org buffer or subtree as an email:
#+BEGIN_SRC emacs-lisp
(general-def org-mode-map "C-c m" #'org-mime-org-buffer-htmlize)
(general-def org-mode-map "C-c s" #'org-mime-org-subtree-htmlize)
#+END_SRC
* Mu4e-alert
Desktop notifications for mu4e emails.
#+BEGIN_SRC emacs-lisp
;; (defun jdormit-get-mu4e-alert-style ()
;; (if (memq window-system '(mac ns))
;; 'notifier
;; 'libnotify))
;;
;; (use-package mu4e-alert
;; :config
;; (setq mu4e-alert-interesting-mail-query
;; (concat
;; "flag:unread maildir:/jeremy-dormitzer-gmail-com/Inbox"
;; " OR flag:unread maildir:/jeremy-dormitzer-net/Inbox"
;; " OR flag:unread maildir:/jeremydormitzer-lola-com/Inbox"
;; " OR flag:unread maildir:/jeremy-getpterotype-com/Inbox"))
;; (mu4e-alert-set-default-style (jdormit-get-mu4e-alert-style))
;; (mu4e-alert-enable-notifications)
;; (mu4e-alert-enable-mode-line-display)
;; (leader-def-key "amu" #'mu4e-alert-view-unread-mails))
#+END_SRC
. ("-a" "jeremydormitzer-lola-com")))))))
#+end_src
* w3m
Browsing the web from Emacs. Relies on having [[http://w3m.sourceforge.net/][w3m]] installed.

View File

@ -7,23 +7,12 @@ tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
account jeremy.dormitzer-gmail.com
account jeremy-dormitzer-gmail-com
from jeremy.dormitzer@gmail.com
user jeremy.dormitzer@gmail.com
passwordeval pass show imap.gmail.com | head -n 1
account jeremy-dormitzer.net
host mail.dormitzer.net
from jeremy@dormitzer.net
user jeremy@dormitzer.net
passwordeval pass show jeremy@dormitzer.net | head -n 1
account jeremy-getpterotype.com
from jeremy@getpterotype.com
user jeremy@getpterotype.com
passwordeval pass show jeremy@getpterotype.com | head -n 1
account jeremydormitzer-lola.com
account jeremydormitzer-lola-com
from jeremydormitzer@lola.com
user jeremydormitzer@lola.com
passwordeval pass show jeremydormitzer@lola.com | head -n 1