Email management, when heavily abstracted, is simple. To start reading email offline on your own PC you need three programs:
Sync email to/from IMAP server (
Manage email on your PC (
Send email (
Once these three parts are working together then email can be downloaded, viewed, and replied to. Getting these programs working is no easy task, however.
My motivation in doing this was the end goal of easily
org capture-ing my
emails and adding them to my master
todo.org file. I thought that by keeping
all of my actionable tasks in one central place I could be more productive. Time
will tell if that assumption is true.
mbsync is a tool written in python to facilitate the downloading and
uploading of mail from an IMAP server. There are other programs for doing this
OfflineIMAP), but I chose
mbsync because it was the easiest for me
to setup, didn't have any weird certificate errors with gmail, and it was
mbsync setup uses two gmail accounts. However, for the sake of
brevity, I have trimmed it down to just use one. The whole
configuration is in my dotfiles repository.
To store passwords on the command line I use the
pass password manager.
To access a command line password manager
mbsync uses the
PassCmd setting to
define a command that will return the password. I use pam gnupg program to
unlock my gnupg key on login I do not have to keep entering my GPG password to
provide my email password to
I dislike the
[Gmail]. prefix that all folders have when downloaded by
default. To solve this problem I have a channel for each of the folders I
download and I can give each of them an explicit file name. For example,
"[Gmail].Sent Mail" is renamed to sent in the configuration snippet below.
Channel sync-gmail-sent Master :gmail-remote:"[Gmail]/Sent Mail" Slave :gmail-local:sent Create Slave
On top of renaming some folders I also disabled some of the folders I don't use
in Gmail's settings. You can do this by going to
All in all my
mbsync config file is simple. If you are looking for more
information about how to set up
mbsync you can find it on the Arch Wiki.
IMAPAccount gmail Host imap.gmail.com User firstname.lastname@example.org PassCmd "pass mail/gmail" SSLType IMAPS CertificateFile /etc/ssl/certs/ca-certificates.crt IMAPStore gmail-remote Account gmail MaildirStore gmail-local Subfolders Verbatim Path ~/.local/share/mail/gmail/ Inbox ~/.local/share/mail/gmail/INBOX Channel sync-gmail-default Master :gmail-remote: Slave :gmail-local: Patterns "INBOX" # Create missing folders everywhere SyncState * Channel sync-gmail-sent Master :gmail-remote:"[Gmail]/Sent Mail" Slave :gmail-local:sent Create Slave Channel sync-gmail-archive Master :gmail-remote:"archive" Slave :gmail-local:archive Create Slave Channel sync-gmail-drafts Master :gmail-remote:"[Gmail]/Drafts" Slave :gmail-local:drafts Create Slave Channel sync-gmail-trash Master :gmail-remote:"[Gmail]/Trash" Slave :gmail-local:trash Create Slave # Get all the channels together into a group. Group gmail Channel sync-gmail-default Channel sync-gmail-sent Channel sync-gmail-trash Channel sync-gmail-drafts Channel sync-gmail-archive
mbsync is set and the root mail folder has been created up you can
mbsync -a to sync all mailboxes or sync a specific account by running
mbsync followed by the account name.
mu is a super fast mail indexer that comes with
mu4e which is an email
client for emacs. Both of them work together to allow a powerful, search based
email interface that is keyboard-driven. When you first start it up you will see
a relatively bare main menu.
From there you can jump to your inbox and start reading and replying to mail.
There are videos that can explain
mu4e a lot better than I can so if you need
an intro I would recommend Mike Zamansky's mu4e video.
I use doom emacs and I haven't tested this config in vanilla emacs so I cannot
guarentee that this will work but I can see no reason why it wouldnt. Basicelly
this config sets up a mail account with specific folders for the mail. It also
msmtp as the mechanism to send a message.
;; ~/.doom.d/config.el (require 'mu4e) ;; use mu4e for e-mail in emacs (setq mail-user-agent 'mu4e-user-agent) (setq mu4e-maildir "/home/alex/.local/share/mail") ;; default (setq mu4e-contexts `( ,(make-mu4e-context :name "clemson" :enter-func (lambda () (mu4e-message "Entering Clemson context") ;; Quicky jump to/move a mail to different folders (setq mu4e-maildir-shortcuts '( ("/clemson/INBOX" . ?i) ("/clemson/sent" . ?s) ("/clemson/trash" . ?t) ("/clemson/drafts" . ?d) ("/clemson/archive" . ?r)))) :leave-func (lambda () (mu4e-message "Leaving Clemson context")) :match-func (lambda (msg) (when msg ;; Clemson has two valid emails for each student (or (mu4e-message-contact-field-matches msg :to "email@example.com") (mu4e-message-contact-field-matches msg :to "firstname.lastname@example.org")))) :vars '( ( user-mail-address . "email@example.com" ) ( user-full-name . "Alex Day" ) ( mu4e-drafts-folder . "/clemson/drafts") ( mu4e-sent-folder . "/clemson/sent") ( mu4e-trash-folder . "/clemson/trash") ( mu4e-refile-folder . "/clemson/archive" ) ( mu4e-compose-signature . (concat "Alex Day")))))) ;; don't save message to Sent Messages, Gmail/IMAP takes care of this (setq mu4e-sent-messages-behavior 'delete) ;; allow for updating mail using 'U' in the main view: (setq mu4e-get-mail-command "mbsync -a") (setq message-send-mail-function 'message-send-mail-with-sendmail) (setq sendmail-program "/usr/bin/msmtp") ;; tell msmtp to choose the SMTP server by the 'from' field in the outgoing email (setq message-sendmail-extra-arguments '("--read-envelope-from")) (setq message-sendmail-f-is-evil 't)
As well as just reading messages in emacs I also wanted some way of capturing
messages with org-capture. To do this I set up a capture template that I could
use while either in a message or hovering over a message on the
(require 'org-mu4e) (setq org-capture-templates ("e" "Email Todo" entry (file+headline "~/doc/org/todo.org" "Inbox") "* TODO %?\nProcess mail from %:fromname on %:subject\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n:PROPERTIES:\n:CREATED: %U\n:END:\n %a" :prepend t))
msmtp to send emails from
mu4e. It handles multiple email addresses by
reading the 'from' field that
mu4e sends along with the email. This program is
the only one I have had absolutely no problems with.
# ~/.config/msmtp/config defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt logfile ~/.config/msmtp/msmtp.log account clemson host smtp.gmail.com port 587 from firstname.lastname@example.org user email@example.com passwordeval "pass mail/clemson" account default : clemson
Show Unread Mail in the Statusbar
I use this script to display the number of unread emails in my status bar. I use slstatus with the status2d patch for dwm to allow colors in the status bar. It should be plug and play if you change the directory it looks for new mail in and have font-awesome installed for the mailbox icon.
#!/usr/bin/env sh # Get the number of new mails in all INBOX folders NEWMAILS=$(du -a ~/.local/share/mail/*/INBOX/new/* 2>/dev/null | wc -l) # Print the number of new mails to the statusbar if there are any if [ "$NEWMAILS" -gt 0 ]; then printf "^b%s^" $(xgetres slstatus.color2) printf "^c%s^" $(xgetres slstatus.background) printf " ﯬ %s" $NEWMAILS else # If there are no new mails then print a block the same color # as the background. This is because slstatus will show the previous # color if it is not overwriten printf "^c%s^^b%s^placeholder^d^" $(xgetres slstatus.background) $(xgetres slstatus.background) fi
I have been reading and writing emails this way for the past couple of weeks and
I could be happier. Namely I haven't really researched how to attach files to
email and when sending emails back and forth from two accounts that
tracking it can get a little confusing. Apart from that, however, I am
satisfied with the workflow that these config files set up.