From bb9fa4e62120374671cbb4abc549b8d8141fb49a Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Mon, 20 Apr 2020 10:34:10 -0400 Subject: [PATCH] Start fresh with a new mu4e config --- emacs/init.org | 386 ++++++++----------------------------------------- msmtp/.msmtprc | 15 +- 2 files changed, 65 insertions(+), 336 deletions(-) diff --git a/emacs/init.org b/emacs/init.org index ec081b8..bbc7386 100755 --- a/emacs/init.org +++ b/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 "%s" - (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 :mime-type :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. diff --git a/msmtp/.msmtprc b/msmtp/.msmtprc index 73980dd..4c71839 100644 --- a/msmtp/.msmtprc +++ b/msmtp/.msmtprc @@ -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