mu4e
is a frontend for memu
mail indexermu
just scans mail folders and indexes them- You tell
mu4e
about your mail folders and what searches you want to use - You can also tell
mu4e
how to change its configuration for different “contexts”
Since we will have two accounts under ~/Mail
now, we need to move the existing mail under a subfolder.
But first, we need to stop mu4e from syncing! Run M-x mu4e-quit
to stop the background sync timer.
Now we can move the Gmail folders into ~/Mail/Gmail
:
cd ~
mv Mail Gmail
mkdir Mail
mv Gmail Mail
We also need to update our .mbsyncrc
to use the new folders:
Path ~/Mail/Gmail/
Inbox ~/Mail/Gmail/Inbox
Test with mbsync
to make sure everything syncs correctly:
mbsync -a
Lastly, reindex with mu
:
mu index --maildir=~/Mail [email protected]
We will update our configuration to configure the Gmail account using mu4e-contexts:
(use-package mu4e
:ensure nil
:config
;; This is set to 't' to avoid mail syncing issues when using mbsync
(setq mu4e-change-filenames-when-moving t)
;; Refresh mail using isync every 10 minutes
(setq mu4e-update-interval (* 10 60))
(setq mu4e-get-mail-command "mbsync -a")
(setq mu4e-maildir "~/Mail")
(setq mu4e-contexts
(list
;; Work account
(make-mu4e-context
:name "Work"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Gmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "[email protected]")
(user-full-name . "System Crafters Gmail")
(mu4e-drafts-folder . "/Gmail/[Gmail]/Drafts")
(mu4e-sent-folder . "/Gmail/[Gmail]/Sent Mail")
(mu4e-refile-folder . "/Gmail/[Gmail]/All Mail")
(mu4e-trash-folder . "/Gmail/[Gmail]/Trash")))))
(setq mu4e-maildir-shortcuts
'(("/Gmail/Inbox" . ?i)
("/Gmail/[Gmail]/Sent Mail" . ?s)
("/Gmail/[Gmail]/Trash" . ?t)
("/Gmail/[Gmail]/Drafts" . ?d)
("/Gmail/[Gmail]/All Mail" . ?a))))
Docs: https://www.djcbsoftware.nl/code/mu/mu4e/Contexts.html Example: https://www.djcbsoftware.nl/code/mu/mu4e/Contexts-example.html
Try out the new context by evaluating the new configuration and run M-x mu4e
.
You can change how the default context is picked by setting mu4e-context-policy
to one of the following values:
ask-if-none
- Ask the first time you enter the view (default)pick-first
- Pick the first context in themu4e-contexts
listalways-ask
- Always ask when entering the main view
We’ll be using a Fastmail account (https://ref.fm/u7703101) for this example. It requires an App Password to connect to the IMAP endpoint:
https://www.fastmail.com/settings/security/devicekeys/new
Now we can add the IMAP configuration for the Fastmail account to our .mbsyncrc
file:
... Gmail configuration from previous video ...
IMAPAccount fastmail
Host imap.fastmail.com
Port 993
User [email protected]
PassCmd "cat ~/.oh-no-another-insecure-password"
SSLType IMAPS
SSLVersions TLSv1.2
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore fastmail-remote
Account fastmail
MaildirStore fastmail-local
Path ~/Mail/Fastmail/
Inbox ~/Mail/Fastmail/INBOX/
Trash ~/Mail/Fastmail/Trash/
SubFolders Verbatim
Channel fastmail
Master :fastmail-remote:
Slave :fastmail-local:
Patterns *
Expunge None
CopyArrivalDate yes
Sync All
Create Both
SyncState *
Now you can sync the new account:
mkdir ~/Mail/Fastmail
mbsync -a
You’ll also need to reindex with mu
to add the new address:
mu index --maildir=~/Mail \
[email protected] \
[email protected]
NOTE: It’s possible you will see an error like this -
mu: mu_store_new_writable: xapian error 'Unable to get write lock on /home/daviwil/.mu/xapian: already locked' (11)
Just kill the running mu
process and run mu index
again:
pkill mu
# run mu index again
Now we can add a new context for the account to mu4e-contexts:
(setq mu4e-contexts
(list
;; Work account
(make-mu4e-context
:name "Work"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Gmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "[email protected]")
(user-full-name . "System Crafters Gmail")
(mu4e-drafts-folder . "/Gmail/[Gmail]/Drafts")
(mu4e-sent-folder . "/Gmail/[Gmail]/Sent Mail")
(mu4e-refile-folder . "/Gmail/[Gmail]/All Mail")
(mu4e-trash-folder . "/Gmail/[Gmail]/Trash")))
;; Personal account
(make-mu4e-context
:name "Personal"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Fastmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "[email protected]")
(user-full-name . "System Crafters Fastmail")
(mu4e-drafts-folder . "/Fastmail/Drafts")
(mu4e-sent-folder . "/Fastmail/Sent")
(mu4e-refile-folder . "/Fastmail/Archive")
(mu4e-trash-folder . "/Fastmail/Trash")))))
After evaluating this configuration, we can launch mu4e
again and switch contexts using the ;
(semicolon) character.
Examples:
- Compose new mail in a context
- Archive a message in a context (show which folder it goes to)
- Reply to a message in a merged search
You can create bookmarks to show merged views of folders across accounts:
(add-to-list 'mu4e-bookmarks '("m:/Fastmail/INBOX or m:/Gmail/Inbox" "All Inboxes" ?i))
This is your e-mail client to build!
- Composing e-mails
- Displaying unread mail count and notifications
- Even more uses for contexts and search queries
- Org Mode integration
Here’s the complete configuration for this episode:
Emacs.org
(use-package mu4e
:ensure nil
:config
;; This is set to 't' to avoid mail syncing issues when using mbsync
(setq mu4e-change-filenames-when-moving t)
;; Refresh mail using isync every 10 minutes
(setq mu4e-update-interval (* 10 60))
(setq mu4e-get-mail-command "mbsync -a")
(setq mu4e-maildir "~/Mail")
(setq mu4e-contexts
(list
;; Work account
(make-mu4e-context
:name "Work"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Gmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "[email protected]")
(user-full-name . "System Crafters Gmail")
(mu4e-drafts-folder . "/Gmail/[Gmail]/Drafts")
(mu4e-sent-folder . "/Gmail/[Gmail]/Sent Mail")
(mu4e-refile-folder . "/Gmail/[Gmail]/All Mail")
(mu4e-trash-folder . "/Gmail/[Gmail]/Trash")))
;; Personal account
(make-mu4e-context
:name "Personal"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Fastmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "[email protected]")
(user-full-name . "System Crafters Fastmail")
(mu4e-drafts-folder . "/Fastmail/Drafts")
(mu4e-sent-folder . "/Fastmail/Sent")
(mu4e-refile-folder . "/Fastmail/Archive")
(mu4e-trash-folder . "/Fastmail/Trash")))))
(setq mu4e-maildir-shortcuts
'(("/Inbox" . ?i)
("/Gmail/[Gmail]/Sent Mail" . ?s)
("/Gmail/[Gmail]/Trash" . ?t)
("/Gmail/[Gmail]/Drafts" . ?d)
("/Gmail/[Gmail]/All Mail" . ?a))))
~/.mbsyncrc
IMAPAccount gmail
Host imap.gmail.com
User [email protected]
PassCmd "cat ~/.oh-no-insecure-password"
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore gmail-remote
Account gmail
MaildirStore gmail-local
Subfolders Verbatim
Path ~/Mail/Gmail/
Inbox ~/Mail/Gmail/Inbox
Channel gmail
Master :gmail-remote:
Slave :gmail-local:
Patterns * ![Gmail]* "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" "[Gmail]/Trash"
Create Both
SyncState *
IMAPAccount fastmail
Host imap.fastmail.com
Port 993
User [email protected]
PassCmd "cat ~/.oh-no-another-insecure-password"
SSLType IMAPS
SSLVersions TLSv1.2
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore fastmail-remote
Account fastmail
MaildirStore fastmail-local
Path ~/Mail/Fastmail/
Inbox ~/Mail/Fastmail/INBOX/
Trash ~/Mail/Fastmail/Trash/
SubFolders Verbatim
Channel fastmail
Master :fastmail-remote:
Slave :fastmail-local:
Patterns *
Expunge None
CopyArrivalDate yes
Sync All
Create Both
SyncState *