index all rss twitter github linkedin email

Álvaro Ramírez

28 May 2018 Trying out mu4e and offlineimap


Managing Email from Emacs. Surely that's crazy-talk, but hey… let's give it a try.

Install offlineimap

Need to sync via imap. Use offlineimap. I'm on macOS, so homebrew is king for installing:

brew install offlineimap

Before can configure offlineimap, we'll need to handle a few things first.

Get a cert fingerprint

Use openssl for getting a certificate fingerprint. From offlineimap's FAQ:

SSL_CERT_DIR="" openssl s_client -connect < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -text -in /dev/stdin

Should give you something like:

SHA1 Fingerprint=AA:BB:CC:DD:EE:DD:FF:AA:00:AA:2A:AA:AA:AA:A8:20:80:AA:A2:AA

Encrypt password

Offlineimap can read passwords in plain text in its .offlineimaprc config file, but that's yuckie. Let's encrypt the password and use gnupg for that. Install it:

brew install gnupg

If you haven't already, generate a key

gpg --full-gen-key

Generate an offlineimap account password file.

echo "YourPassword" | gpg --encrypt --recipient "Your Name" -o ~/.offlineimap_accountname.gpg

Python password wrapper

Based on Fabian's Encrypt OfflineIMAP and msmtp password with GnuPG, I created ~/ with:

import os
import subprocess

def read_password(path):
  return subprocess.check_output(["gpg\n", "--quiet\n", "--batch\n", "-d\n", os.path.expanduser(path)]).strip()

ps. Alternatively, see The homely Mutt's section to store password in macOS's keychain.

Configure offlineimap

Offlineimap uses ~/.offlineimaprc for configuration. We now have all we need to put the configuration together:

accounts = Personal

# Load this python file.
pythonfile = ~/

[Account Personal]
localrepository = Personal-Local

remoterepository = Personal-Remote

# After syncing, let mu index it.
postsynchook = mu index --maildir ~/stuff/active/Mail

# Sync imap every 5 minutes.
autorefresh = 5

# Alternate between 10 quick syncs and full syncs.
quick = 10

[Repository Personal-Local]
type = Maildir
localfolders = ~/stuff/active/Mail/Personal

[Repository Personal-Remote]
type = IMAP
remotehost =
remoteuser = your_user_name

# Use function defined in to read the password.
remotepasseval = read_password("~/.offlineimap_personal_account_password.gpg")

# Use the SHA1 fingerprint retrieved with openssl.
cert_fingerprint = aabbccddeeddffaa00aa2aaaaaaaa82080aaa2aa

Cert file

You can use macOS's certificates from Keychain Access -> System Roots -> Certificates, select all, and ⌘-⇧-e (for export items). Save to ~/certs.pem and use offlineimap configutation:

sslcacertfile = /path/to/certs.pem

Another option is executing lib/ from curl's tarball to generate ca-bundle.crt, using certdata.txt from Mozilla's source tree.

Install mu4e

Manually modified mu4e recipe to pick up my Emacs binary. TIL about homebrew's edit command:

brew edit mu

Changed the one line:

  • ENV["EMACS"] = "no" if build.without? "emacs"
  • ENV["EMACS"] = "/Users/alvaro/homebrew/Cellar/emacs-plus/26.1-rc1_2/bin/emacs"

Finally installed mu4e:

brew install mu

Configure mu4e

Lastly, configure mu4e:

(add-to-list 'load-path
             (expand-file-name "~/homebrew/share/emacs/site-lisp/mu/mu4e"))
(use-package mu4e
  ;; Update mail using 'U' in main view:
  (setq mu4e-get-mail-command "offlineimap")
  (setq mu4e-view-show-addresses t)
  (setq mu4e-attachment-dir (expand-file-name "~/Downloads/"))
  (setq mu4e-maildir "path/to/Mail")
  (setq mu4e-html2text-command "w3m -T text/html") ;; alternatively "textutil -stdin -format html -convert txt -stdout"
  (setq mu4e-user-mail-address-list '(""
  (setq mu4e-context-policy 'pick-first)
  (setq mu4e-compose-context-policy 'always-ask)
  (setq mu4e-contexts
          :name "domain1"
          :enter-func (lambda () (mu4e-message "Entering context"))
          :leave-func (lambda () (mu4e-message "Leaving context"))
          :match-func (lambda (msg)
                        (when msg
                           msg '(:from :to :cc :bcc) "")))
          :vars '((user-mail-address . "")
                  (user-full-name . "My name")
                  (mu4e-sent-folder . "/Domain1/Sent")
                  (mu4e-drafts-folder . "/Domain1/Drafts")
                  (mu4e-trash-folder . "/Domain1/Trash")
                  (mu4e-compose-signature . nil)
                  (mu4e-compose-format-flowed . nil)
                  (smtpmail-smtp-user . "")
                  (smtpmail-smtp-server . "")
                  (smtpmail-smtp-service . 587)))
          :name "domain2"
          :enter-func (lambda () (mu4e-message "Entering context"))
          :leave-func (lambda () (mu4e-message "Leaving context"))
          :match-func (lambda (msg)
                        (when msg
                           msg '(:from :to :cc :bcc) "")))
          :vars '((user-mail-address . "")
                  (user-full-name . "My name")
                  (mu4e-sent-folder . "/Domain2/Sent")
                  (mu4e-drafts-folder . "/Domain2/Drafts")
                  (mu4e-trash-folder . "/Domain2/Trash")
                  (mu4e-compose-signature . nil)
                  (mu4e-compose-format-flowed . nil)
                  (smtpmail-smtp-user . "")
                  (smtpmail-smtp-server . "")
                  (smtpmail-smtp-service . 587))))))

(use-package smtpmail
  (setq smtpmail-stream-type 'starttls)
  (setq smtpmail-debug-info t)
  (setq smtpmail-warn-about-unknown-extensions t)
  (setq smtpmail-queue-mail t)
  (setq smtpmail-default-smtp-server nil)
  ;; Created with mu mkdir path/to/Mail/queue
  ;; Also avoid indexing.
  ;; touch path/to/Mail/queue/.noindex
  (setq smtpmail-queue-dir "path/to/Mail/queue/cur"))

(use-package message
  (setq message-send-mail-function 'smtpmail-send-it))


Create an ~/.authinfo file for sendmail authentication with:

machine login password somepassword1
machine login password somepassword2

Encrypt ~/.authinfo with M-x epa-encrypt-file. Keep ~/.authinfo.gpg and delete ~/.authinfo.

Mu4e helpful references