My Email Setup
For the past few months, I have used the following email setup:
Incoming mail → mbsync (MRA) → mu (email indexer) → mu4e (MUA) → msmtp (SMTP client) → Outgoing mail
Summary
- mbsync synchronises the local maildirs via IMAP with the email accounts themselves. I found it to be faster than OfflineIMAP.
- mu indexes messages and makes them easier to search.
- mu4e is the Emacs-based email client included with mu.
- msmtp sends outgoing messages over SMTP.
Setup
Installation
First, install the relevant tools. Under Debian, one would install the following packages:
# apt install isync mu4e msmtp
Preparation
Next, create the directories that will contain your maildirs. Change the path and account names to match your preferences:
$ mkdir -p ~/Mail/{Main,Personal,Work}
I also recommend creating your signature blocks at this point. This tutorial uses files in ~/doc/signatures
as an example. See the message-signature-file
variables in the below mu4e config for examples.
Configuring mbsync
Write your ~/.mbsyncrc
. Here is an example for 3 accounts:
IMAPAccount Main
Host imap.example.net
User foo@example.net
Pass hunter2
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore Main-remote
Account Main
MaildirStore Main-local
Path ~/Mail/Main/
Inbox ~/Mail/Main/inbox
Channel Main-default
Master :Main-remote:
Slave :Main-local:Inbox
Channel Main-sent
Master :Main-remote:"[Gmail]/Sent Mail"
slave :Main-local:Sent
Channel Main-trash
Master :Main-remote:"[Gmail]/Trash"
slave :Main-local:Trash
Channel Main-archive
Master :Main-remote:"[Gmail]/All Mail"
slave :Main-local:All
Channel Main-junk
Master :Main-remote:"[Gmail]/Spam"
slave :Main-local:Junk
Channel Main-drafts
Master :Main-remote:"[Gmail]/Drafts"
slave :Main-local:Drafts
Create Both
Expunge Both
SyncState *
Group Main
Channel Main-default
Channel Main-sent
Channel Main-trash
Channel Main-archive
Channel Main-junk
IMAPAccount Personal
Host imap.example.net
User bar@example.net
Pass hunter2
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore Personal-remote
Account Personal
MaildirStore Personal-local
Path ~/Mail/Personal/
Inbox ~/Mail/Personal/inbox
Channel Personal-default
Master :Personal-remote:
Slave :Personal-local:Inbox
Channel Personal-sent
Master :Personal-remote:"[Gmail]/Sent Mail"
slave :Personal-local:Sent
Channel Personal-trash
Master :Personal-remote:"[Gmail]/Trash"
slave :Personal-local:Trash
Channel Personal-archive
Master :Personal-remote:"[Gmail]/All Mail"
slave :Personal-local:All
Channel Personal-junk
Master :Personal-remote:"[Gmail]/Spam"
slave :Personal-local:Junk
Channel Personal-sent
Master :Personal-remote:"[Gmail]/Sent Mail"
slave :Personal-local:Sent
Create Both
Expunge Both
SyncState *
Group Personal
Channel Personal-default
Channel Personal-sent
Channel Personal-trash
Channel Personal-archive
Channel Personal-junk
IMAPAccount Work
Host imap.example.net
User baz@example.net
Pass hunter2
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore Work-remote
Account Work
MaildirStore Work-local
Path ~/Mail/Work/
Inbox ~/Mail/Work/inbox
Channel Work-default
Master :Work-remote:
Slave :Work-local:Inbox
Channel Work-sent
Master :Work-remote:"[Gmail]/Sent Mail"
slave :Work-local:Sent
Channel Work-trash
Master :Work-remote:"[Gmail]/Trash"
slave :Work-local:Trash
Channel Work-archive
Master :Work-remote:"[Gmail]/All Mail"
slave :Work-local:All
Channel Work-junk
Master :Work-remote:"[Gmail]/Spam"
slave :Work-local:Junk
Channel Work-drafts
Master :Work-remote:"[Gmail]/Drafts"
slave :Work-local:Drafts
Create Both
Expunge Both
SyncState *
Group Work
Channel Work-default
Channel Work-sent
Channel Work-trash
Channel Work-archive
Channel Work-junk
The location of CertificateFile
may vary based on your system.
Finally, make ~/.mbsyncrc
readable and writable only by the owner, for privacy:
$ chmod 600 ~/.mbsyncrc
Configuring msmtp
~/.msmtprc
should look something like this:
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
# Main
account Main
host smtp.example.net
port 587
from foo@example.net
user foo@example.net
password hunter2
# Personal
account Personal
host smtp.example.net
port 587
from bar@example.net
user bar@example.net
password hunter2
# Work
account Work
host smtp.example.net
port 587
from baz@example.net
user baz@example.net
password hunter2
account default : Main
As with mbsync’s CertificateFile
, the location of tls_trust_file
may vary based on your system.
As with ~/.mbsyncrc
above, you should make ~/.msmtprc
readable and writable only by the owner. This is especially important with msmtp, as it will refuse to run otherwise.
$ chmod 600 ~/.msmtprc
msmtpqueue
msmtpqueue is a small collection of scripts to queue outgoing messages and then send them later. Under Debian, it is available in /usr/share/doc/msmtp/examples/msmtpqueue
. I copied the scripts to my personal ~/local/bin
directory and then edited them for my own use. See /usr/share/doc/msmtp/examples/msmtpqueue/README
for more information.
There is also msmtpq
, which I have not tried.
Configuring mu4e
mu4e is configured in your Emacs init file. Here is an example:
(require 'mu4e)
;; Make mu4e Emacs's default email client
(setq read-mail-command 'mu4e
mail-user-agent 'mu4e-user-agent)
;; Where the messages are
(setq mu4e-maildir "~/Mail")
;; How to get mail
(setq mu4e-get-mail-command "mbsync -a"
mu4e-update-interval 300)
;; How to send mail
;; (Be sure to point sendmail-program to the proper path for msmtp-enqueue.sh!)
(setq message-send-mail-function 'message-send-mail-with-sendmail
sendmail-program "/home/user/bin/msmtp-enqueue.sh")
;; Gmail needs this
(setq mu4e-sent-messages-behavior 'delete)
;; Display To: header in headers view
(setq mu4e-headers-fields '((:human-date . 12)
(:flags . 6)
(:from . 15)
(:to . 12)
(:subject)))
;; Bookmarks
(setq mu4e-bookmarks
`( ,(make-mu4e-bookmark
:name "Unread messages"
:query "flag:unread AND NOT \"maildir:/Main/Junk\" AND NOT \"maildir:/Personal/Junk\" AND NOT \"maildir:/Work/Junk\""
:key ?u)
,(make-mu4e-bookmark
:name "Today's messages"
:query "date:today..now AND NOT \"maildir:/Main/Junk\" AND NOT \"maildir:/Personal/Junk\" AND NOT \"maildir:/Work/Junk\""
:key ?t)
,(make-mu4e-bookmark
:name "Last 7 days"
:query "date:7d..now AND NOT \"maildir:/Main/Junk\" AND NOT \"maildir:/Personal/Junk\" AND NOT \"maildir:/Work/Junk\""
:key ?w)
,(make-mu4e-bookmark
:name "Inboxes"
:query "\"maildir:/Main/INBOX\" OR \"maildir:/Personal/INBOX\" OR \"maildir:/Work/INBOX\""
:key ?i)
,(make-mu4e-bookmark
:name "Sent messages"
:query "\"maildir:/Main/Sent\" OR \"maildir:/Personal/Sent\" OR \"maildir:/Work/Sent\""
:key ?s)
,(make-mu4e-bookmark
:name "Spam"
:query "\"maildir:/Main/Junk\" OR \"maildir:/Personal/Junk\" OR \"maildir:/Work/Junk\""
:key ?j)))
For multiple email accounts, we will use contexts. If you publish your Emacs config, e.g., in version control, be aware that this section will contain passwords and other personally identifiable information.
(require 'mu4e-context)
(setq mu4e-contexts
`( ,(make-mu4e-context
:name "Main"
:enter-func (lambda () (mu4e-message "Entering Main context"))
:leave-func (lambda () (mu4e-message "Leaving Main context"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg :to "foo@example.net")))
:vars '((user-email-address . "foo@example.net")
(user-mail-address . "foo@example.net")
(user-full-name . "Someone")
(mu4e-sent-folder . "/Main/Sent")
(mu4e-drafts-folder . "/Main/Drafts")
(mu4e-trash-folder . "/Main/Trash")
(mu4e-refile-folder . "/Main/All")
(message-sendmail-extra-arguments . "-a Main")
(mail-host-address . "example.net")
(mu4e-compose-signature . (with-temp-buffer (insert-file-contents "~/doc/signatures/Main") (buffer-string)))
(message-signature-file . "~/doc/signatures/Main")))
,(make-mu4e-context
:name "Personal"
:enter-func (lambda () (mu4e-message "Switch to the Personal context"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg :to "bar@example.net")))
:vars '((user-email-address . "bar@example.net")
(user-mail-address . "bar@example.net")
(user-full-name . "John Smith")
(mu4e-sent-folder . "/Personal/Sent")
(mu4e-drafts-folder . "/Personal/Drafts")
(mu4e-trash-folder . "/Personal/Trash")
(mu4e-refile-folder . "/Personal/All")
(message-sendmail-extra-arguments . "-a Personal")
(mail-host-address . "example.net")
(mu4e-compose-signature . (with-temp-buffer (insert-file-contents "~/doc/signatures/Personal") (buffer-string)))
(message-signature-file . "~/doc/signatures/Personal")))
,(make-mu4e-context
:name "Work"
:enter-func (lambda () (mu4e-message "Switch to the Work context"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg :to "baz@example.net")))
:vars '((user-email-address . "baz@example.net")
(user-mail-address . "baz@example.net")
(user-full-name . "John Smith")
(mu4e-sent-folder . "/Work/Sent")
(mu4e-drafts-folder . "/Work/Drafts")
(mu4e-trash-folder . "/Work/Trash")
(mu4e-refile-folder . "/Work/All")
(message-sendmail-extra-arguments . "-a Work")
(mail-host-address . "example.net")
(mu4e-compose-signature . (with-temp-buffer (insert-file-contents "~/doc/signatures/Work") (buffer-string)))
(message-signature-file . "~/doc/signatures/Work")))))
(setq mu4e-context-policy 'pick-first
mu4e-compose-context-policy 'ask)
Initialisation
Synchronise the maildirs and then index the messages:
$ mbsync -a
$ mu index --maildir="$HOME/Mail"
cronjobs
You can have cron
synchronise your maildirs and send pending messages automatically. Put this shell script in ~/bin
or a similar directory, name it get-send-mail
(or similar), and make it executable with chmod +x
:
#!/bin/sh
# Check if we are online; replace with something more appropriate for your setup
ping -c 1 -w 2 example.net > /dev/null
if [ "$?" -eq 0 ]; then
mbsync -aq
/home/user/bin/msmtp-runqueue.sh > /dev/null
fi
Be sure to point to the proper path for msmtp-runqueue.sh
. You can now put something like this in your crontab:
@reboot /home/user/bin/get-send-mail
*/5 * * * * /home/user/bin/get-send-mail
It should run at boot and every 5 minutes.
Usage
Simply restart Emacs, and then start mu4e with M-x mu4e. For more information, see the mu4e manual: (info "(mu4e)")