How to use mu4e with multiple accounts in Emacs

I was very unsatisfied with my email setup. In the past, I used mutt, gnus and Thunderbird. However, in mutt and Thunderbird, I missed proper Emacs keybindings, and gnus felt to slow for me. I recently heard about mu4e. mu4e is an email system for Emacs. It’s built on top of mu.

In this post, I will showcase my mu4e and offlineimap setup because I like mu4e a lot by now. mu4e is fast and lets me write emails within Emacs :). Before I showcase my setup, I want to say that mu4e comes with excellent documentation that is worth reading.

I use three email accounts: A private email account, where I do most of my emails, a Gmail account and an email account for the university. My goals are:

  • Search through all the emails from all three accounts.
  • Write emails from my private and Gmail account.
  • If I get an email, for example on Gmail, I want mu4e to pick my Gmail address if I respond to the email.

To use mu and mu4e, you need to have all your emails locally available. To make all the emails locally available, I use offlineimap. The following shows my offlineimap config. It pulls all the emails from my three accounts and saves them into different directories (the university account is not listed):

[general]
accounts = T-Online,Gmail
maxsyncaccounts = 3

[Account T-Online]
localrepository = T-Online-Local
remoterepository = T-Online-Remote

[Repository T-Online-Local]
type = Maildir
localfolders = ~/Maildir/T-Online

[Repository T-Online-Remote]
type = IMAP
remotehost = secureimap.t-online.de
remoteuser = felix.weilbach@t-online.de
remotepass = SUPER_SECRET_PASSWORD_1
realdelete = no
maxconnections = 3
sslcacertfile = /etc/pki/tls/certs/ca-bundle.crt


[Account Gmail]
localrepository = Gmail-Local
remoterepository = Gmail-Remote

[Repository Gmail-Local]
type = Maildir
localfolders = ~/Maildir/Gmail

[Repository Gmail-Remote]
type = IMAP
remotehost = imap.gmail.com
remoteuser = feweilbach@gmail.com
remotepass = SUPER_SECRET_PASSWORD_2
realdelete = no
ssl = yes
sslcacertfile = /etc/pki/tls/certs/ca-bundle.crt
maxconnections = 1

A important point is here that you need to adjust the certificates file /etc/pki/tls/certs/ca-bundle.crt based on your distro. In this example I used Fedora.

Now run offlineimap for the first time with

offlineimap

Next, we need to set up mu:

mu init --maildir=~/Maildir --my-address=felix.weilbach@t-online.de --my-address=feweilbach@gmail.com --my-address=felix.weilbach@student.uni-augsburg.de
mu index

If finished successfully, we can configure mu4e within Emacs:

;; Open mu4e when pressing F12
(global-set-key (kbd "<f12>") #'mu4e)

(require 'mu4e)

(defun enter-mu4e-context-tonline ()
  (setq mu4e-sent-folder   "/T-Online/INBOX.Sent"
        mu4e-drafts-folder "/T-Online/INBOX.Drafts"
        mu4e-trash-folder  "/T-Online/INBOX.Trash"
        mu4e-refile-folder "/T-Online/INBOX.Archive"

        mu4e-maildir-shortcuts
        '((:maildir "/T-Online/INBOX"       :key ?i)
          (:maildir "/T-Online/INBOX.Sent"  :key ?s)
          (:maildir "/T-Online/INBOX.Trash" :key ?t)))

  (require 'smtpmail)
  (setq message-send-mail-function 'smtpmail-send-it
        starttls-use-gnutls t
        smtpmail-starttls-credentials '(("securesmtp.t-online.de" 465 nil nil))
        smtpmail-auth-credentials
        '(("securesmtp.t-online.de" 465 "felix.weilbach@t-online.de" nil))
        smtpmail-default-smtp-server "securesmtp.t-online.de"
        smtpmail-smtp-server "securesmtp.t-online.de"
        smtpmail-smtp-service 465
        smtpmail-stream-type 'ssl)

  )

(defun enter-mu4e-context-gmail ()
  (setq mu4e-sent-folder   "/Gmail/[Gmail].Sent Mail"
        mu4e-drafts-folder "/Gmail/[Gmail].Drafts"
        mu4e-trash-folder  "/Gmail/[Gmail].Trash"
        mu4e-refile-folder "/Gmail/[Gmail].Archive"

        mu4e-maildir-shortcuts
        '((:maildir "/Gmail/INBOX"              :key ?i)
          (:maildir "/Gmail/[Gmail].Sent Mail"  :key ?s)
          (:maildir "/Gmail/[Gmail].Trash"      :key ?t)
          (:maildir "/Gmail/[Gmail].All Mail"   :key ?a)))

  (require 'smtpmail)
  (setq message-send-mail-function 'smtpmail-send-it
        starttls-use-gnutls t
        smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
        smtpmail-auth-credentials
        '(("smtp.gmail.com" 587 "feweilbach@gmail.com" nil))
        smtpmail-default-smtp-server "smtp.gmail.com"
        smtpmail-smtp-server "smtp.gmail.com"
        smtpmail-smtp-service 587
        smtpmail-stream-type nil))

(setq mu4e-contexts
      `(,(make-mu4e-context
          :name "T-Online"
          :enter-func (lambda () (progn
                                   (mu4e-message "Entering T-Online Context")
                                   (enter-mu4e-context-tonline)
                                   ))
          :leave-func (lambda () (mu4e-message "Leave T-Online Context"))
          ;; We match based on the contact-fields of the message
	        :match-func (lambda (msg)
			                  (when msg
			                    (mu4e-message-contact-field-matches msg
			                      :to "felix.weilbach@t-online.de")))
          :vars '((user-mail-address . "felix.weilbach@t-online.de"  )
		              (user-full-name . "Felix Weilbach" )
                  ))

        ,(make-mu4e-context
          :name "Gmail"
          :enter-func (lambda () (progn
                                   (mu4e-message "Entering Gmail Context")
                                   (enter-mu4e-context-gmail)
                                   ))
          :leave-func (lambda () (mu4e-message "Leave Gmail Context"))
          ;; We match based on the contact-fields of the message
	        :match-func (lambda (msg)
			                  (when msg
			                    (mu4e-message-contact-field-matches msg
			                      :to "feweilbach@gmail.com")))
          :vars '((user-mail-address . "feweilbach@gmail.com"  )
		              (user-full-name . "Felix Weilbach" )
                  ))
        ))

(setq mu4e-context-policy 'pick-first
      mu4e-get-mail-command "offlineimap"
      mu4e-update-interval 120
      mu4e-sent-messages-behavior 'delete
      mu4e-use-maildirs-extension t
      mu4e-enable-async-operations t
      mu4e-attachment-dir "~/Downloads"
      mu4e-confirm-quit nil

      ;; Prefer text over html email
      mu4e-view-html-plaintext-ratio-heuristic  most-positive-fixnum

      ;; mu4e-compose-context-policy nil
      )

;; Use flyspell for spell checking and use german dictionary.
(add-hook 'mu4e-compose-mode-hook '(lambda ()
                                     (progn
                                       (flyspell-mode)
                                       (ispell-change-dictionary "de_DE")
                                       )))

You can find my complete Emacs configuration here. The mu4e is in this file.