In Email Heaven with Emacs, mu4e, and mbsync

In Email Heaven with Emacs, mu4e, and mbsync

23 Nov 2021
Email, Emacs, MacOS, Mu4e

All mail clients suck. This one just sucks less.
Mutt

I was a long-time mutt user. Come to think of it, I think the reason why I learned Emacs was because that was what $EDITOR was set to, and I needed to know how to get around so I could send email via mutt.

As more of my life has gotten sucked into Emacs, I’ve wanted to move my email into Emacs as well. I’ve been using a combination of mu4e and isync/mbsync to manage my email. I’m using Pobox for email hosting, and my inbox has never been so consistently near empty before.

Email Setup #

I keep the following in a file that I require lazily in my Emacs config:

(setq mu4e-mu-binary "/usr/local/bin/mu")

;; Folders
(setq mu4e-sent-folder "/Sent")
(setq mu4e-drafts-folder "/Drafts")
(setq mu4e-trash-folder "/Trash")
(setq mu4e-refile-folder "/Archive")
(setq mu4e-attachment-dir "~/Downloads")

;; Signature stuffs
;; (setq user-full-name "")
;; (setq user-mail-address "")
;; (setq mu4e-compose-signature "")

;; (setq smtpmail-smtp-server "")
;; (setq smtpmail-smtp-user "")
(setq smtpmail-stream-type 'starttls)
(setq smtpmail-smtp-service 587)

;; When mu upgrades, run `byte-recompile-directory' on this folder
;; (byte-recompile-directory  "/usr/local/Cellar/mu/1.6.8/share/emacs/site-lisp/mu/mu4e")
(add-to-list 'load-path "/usr/local/Cellar/mu/1.6.8/share/emacs/site-lisp/mu/mu4e")
(require 'mu4e)

(setq mu4e-completing-read-function 'completing-read)
(setq mu4e-view-auto-mark-as-read t)
(setq mu4e-view-show-addresses t)
(setq mu4e-view-show-images t)

;; Org-mode integration
(setq org-mu4e-link-query-in-headers-mode nil)

;; give me ISO(ish) format date-time stamps in the header list
(setq  mu4e-headers-date-format "%Y-%m-%d %H:%M")

;; allow for updating mail using 'U' in the main view:
(setq mu4e-get-mail-command "mbsync -a")

;; Fixes problem with duplicate UID errors (see
;; http://pragmaticemacs.com/emacs/fixing-duplicate-uid-errors-when-using-mbsync-and-mu4e/)
(setq mu4e-change-filenames-when-moving t)

;; customize the reply-quote-string
;; M-x find-function RET message-citation-line-format for docs
(setq message-citation-line-format "%N on %Y-%m-%d %H:%M %Z:\n")
(setq message-citation-line-function 'message-insert-formatted-citation-line)

;; Turn on word-wrap automatically when viewing emails
(add-hook 'mu4e-view-mode-hook 'turn-on-visual-line-mode)
(add-hook 'mu4e-compose-mode-hook 'turn-on-visual-line-mode)

;; Don't hard-wrap my emails as I write!
(add-hook 'mu4e-compose-mode-hook (lambda () (auto-fill-mode -1)))

;; But make sure they flow on the receving end
(setq mu4e-compose-format-flowed t)

;; How to send messages
(setq message-send-mail-function 'smtpmail-send-it)

(define-key global-map (kbd "s-m") 'mu4e)

And here’s how I get the lazy loading:

(defvar lazy-email-loadedp nil)
(defun lazy-boot-email ()
  (interactive)
  (when (not lazy-email-loadedp)
    (message "Loading email config...")
    (load-file "~/.dotfiles/email-setup.el")
    (setq lazy-email-loadedp t)
    (message "Loading email config...done")
    (mu4e)))

(define-key global-map (kbd "s-m") 'lazy-boot-email)

That defines s-m to the function that loads the email config file. When that file gets loaded, it overwrites the keybinding for s-m so that it doesn’t try to reload the file.

Mastodon