Start fresh with a new mu4e config
This commit is contained in:
parent
fb981f0f16
commit
bb9fa4e621
386
emacs/init.org
386
emacs/init.org
@ -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")
|
||||
mu4e-contexts
|
||||
(let ((per-dir "/jeremy-dormitzer-gmail-com")
|
||||
(pterotype-dir "/jeremy-getpterotype-com")
|
||||
(lola-dir "/jeremydormitzer-lola-com"))
|
||||
`(,(make-mu4e-context
|
||||
:name "Pterotype"
|
||||
: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
|
||||
"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)
|
||||
(mu4e-get-mail-command . "mbsync jeremy-dormitzer-gmail-com")
|
||||
(message-sendmail-extra-arguments
|
||||
. ("-a" "jeremy.dormitzer-gmail.com"))))
|
||||
,(make-mu4e-context
|
||||
:name "Lola"
|
||||
:match-func (lambda (msg)
|
||||
(when msg ())
|
||||
(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)
|
||||
(mu4e-get-mail-command . "mbsync jeremydormitzer-lola-com")
|
||||
(message-sendmail-extra-arguments
|
||||
. ("-a" "jeremydormitzer-lola.com"))))))
|
||||
;; 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-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
|
||||
mu4e-compose-context-policy 'ask
|
||||
mu4e-contexts
|
||||
`(,(make-mu4e-context
|
||||
:name "Personal Gmail"
|
||||
:match-func (lambda (msg)
|
||||
(when msg
|
||||
(string-match-p
|
||||
"jeremy-dormitzer-gmail-com"
|
||||
(mu4e-message-field msg :path))))
|
||||
: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"))))
|
||||
,(make-mu4e-context
|
||||
:name "Lola Gmail"
|
||||
:match-func (lambda (msg)
|
||||
(when msg
|
||||
(string-match-p
|
||||
"jeremydormitzer-lola-com"
|
||||
(mu4e-message-field msg :path))))
|
||||
: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")))))))
|
||||
#+end_src
|
||||
|
||||
* w3m
|
||||
Browsing the web from Emacs. Relies on having [[http://w3m.sourceforge.net/][w3m]] installed.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user