Intro
This post is the second part about GnuPG, password management, email, signing and
encrypting emails and git commit signing. The first posts talked about GnuPG key
generation, password management using pass
, how to sign git commits and how Emacs
connects with most of it. This post will focus on how to manage mails in Emacs with Mu4e
and how to signing and encrypting messages with GnuPG. As the posts cover a lot of
ground step by step instructions are not desirable. Links to more detailed resources can
be found in each section. The main goal is to provide a quick but informative overview
and give inspiration for further research.
The big picture is. Use mbsync
to retrieve mails using imap. Mu4e for "Maildir
indexer/searcher and Emacs client (mu4e)". All cridentials that are related to imap and
SMTP are stored in pass
's password store and are version controlled using git. GnuPG
keys are used to encrypt the password store and to signing and encryting emails.
The layout of the post:
- Environment; versions of the software (minus the ones already described in the first post).
- Mbsync; how to configure mbsync and how to take advantage of pass.
- Mu4e; Emacs config and how to sign and encrypt emails.
If things are unclear, please contact me via twitter!
Environment
Version of the software in use. OS, GnuPG, Pass and Emacs versions can be found in the first post.
#+BEGIN_SRC shell :results output code
mbsync --version
#+END_SRC
#+RESULTS:
#+begin_src shell
isync 1.3.1
#+end_src
#+BEGIN_SRC shell :results output code
mu --version
#+END_SRC
#+RESULTS:
#+begin_src shell
mu (mail indexer/searcher) version 1.4.10
Copyright (C) 2008-2020 Dirk-Jan C. Binnema
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
#+end_src
Mbsync
More details about isync/mbsync can be found here:
- https://wiki.archlinux.org/index.php/isync
- https://www.djcbsoftware.nl/code/mu/mu4e.html
- https://cestlaz.github.io/posts/using-emacs-39-mu4e/
- http://www.macs.hw.ac.uk/~rs46/posts/2014-01-13-mu4e-email-client.html
Install
mbsync/isync exists in Arch standard repos.
pacman -S isync
Config files
The config is more or less stolen from the Arch Wiki. PassCmd is using long arguments instead of short ones. Just to make things more describing.
Note that "PassCmd" gpg files is located in the pass
password store.
#+BEGIN_SRC shell :results output code
cat ~/.mbsyncrc
#+END_SRC
#+RESULTS:
#+begin_src shell
IMAPAccount gmail
Host imap.gmail.com
User jherrlin@gmail.com
PassCmd "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.password-store/mbsync/gmail.gpg"
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"
Create Both
SyncState *
IMAPAccount lnu
Host imap.gmail.com
User jh222jx@student.lnu.se
PassCmd "gpg2 --quiet --for-your-eyes-only --no-tty --decrypt ~/.password-store/mbsync/lnu.gpg"
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt
IMAPStore lnu-remote
Account lnu
MaildirStore lnu-local
Subfolders Verbatim
Path ~/.mail/lnu/
Inbox ~/.mail/lnu/Inbox
Channel lnu
Master :lnu-remote:
Slave :lnu-local:
Create Both
SyncState *
#+end_src
Lets create the mbsync/gmail and mbsync/lnu files.
pass insert mbsync/gmail
pass insert mbsync/lnu
The layout of the file should be just the password on the first row and nothing more.
#+BEGIN_SRC shell :results output code
gpg --decrypt ~/.password-store/mbsync/gmail.gpg
#+END_SRC
#+RESULTS:
#+begin_src shell
<PASSWORD>
#+end_src
Create needed folders.
mkdir -p ~/.mail/gmail ~/.mail/lnu
And sync all configs.
mbsync -a
Now all of your emails should be in your ~/.mail
dir.
Mu4e
Here are some resources.
Install
Mu4e is installed from aur using:
mkdir -p ~/aur
cd $_
git clone https://aur.archlinux.org/mu.git
cd mu
makepkg -si
Init
Mu points to the same directory as mbsync. Before usage indexing needs to be done.
mu init --maildir=~/.mail --my-address=jherrlin@gmail.com --my-address=jh222jx@student.lnu.se
mu index
Emacs config
This is more or less all of the config for using mu4e in Emacs.
I will only cover the parts important to this post.
(setq auth-sources '(password-store))
and (auth-source-pass-enable)
tells Emacs
that passwords for smtp is in the pass
password store. auth-source-pass
looks for
credentials in a certain order within the password store. The file that is found for
the gmail account is ~/.password-store/smtp.gmail.com/jherrlin@gmail.com.gpg
. It's
the smtpmail-smtp-server
and smtpmail-smtp-user
vars that points it to that
location.
There is a function on message-send-hook
that asks to sign or encrypt the message
before sending. mml-secure-message-sign-pgpmime
and
mml-secure-message-encrypt-pgpmime
will automatically pick up your gpg keys and add
correct data to the message before sending.
#+BEGIN_SRC shell :results output code
cat ~/.emacs.d/mail.el
#+END_SRC
#+RESULTS:
#+begin_src shell
(require 'mu4e)
(require 'org-mu4e)
(require 'mu4e-contrib)
(require 'smtpmail)
(auth-source-pass-enable)
(setq auth-source-debug t)
(setq auth-source-do-cache nil)
(setq auth-sources '(password-store))
(setq message-kill-buffer-on-exit t)
(setq message-send-mail-function 'smtpmail-send-it)
(setq mu4e-attachment-dir "~/Downloads")
(setq mu4e-change-filenames-when-moving t)
(setq mu4e-completing-read-function 'completing-read)
(setq mu4e-compose-complete-addresses t)
(setq mu4e-compose-context-policy nil)
(setq mu4e-compose-dont-reply-to-self t)
(setq mu4e-compose-keep-self-cc nil)
(setq mu4e-context-policy 'pick-first)
(setq mu4e-get-mail-command "mbsync -a")
(setq mu4e-headers-date-format "%d-%m-%Y %H:%M")
(setq mu4e-headers-fields '((:human-date . 20)
(:flags . 6)
(:mailing-list . 10)
(:from . 22)
(:subject)))
(setq mu4e-headers-include-related t)
(setq mu4e-sent-messages-behavior 'delete)
(setq mu4e-view-show-addresses t)
(setq mu4e-view-show-images t)
(setq smtpmail-debug-info t)
(setq smtpmail-stream-type 'starttls)
(setq mm-sign-option 'guided)
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
(defun sign-or-encrypt-message ()
(let ((answer (read-from-minibuffer "Sign or encrypt?\nEmpty to do nothing.\n[s/e]: ")))
(cond
((string-equal answer "s") (progn
(message "Signing message.")
(mml-secure-message-sign-pgpmime)))
((string-equal answer "e") (progn
(message "Encrypt and signing message.")
(mml-secure-message-encrypt-pgpmime)))
(t (progn
(message "Dont signing or encrypting message.")
nil)))))
(add-hook 'message-send-hook 'sign-or-encrypt-message)
(setq mu4e-contexts
`( ,(make-mu4e-context
:name "gmail"
:enter-func (lambda ()
(mu4e-message "Entering gmail context")
(when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
(revert-buffer)))
:leave-func (lambda ()
(mu4e-message "Leaving gmail context")
(when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
(revert-buffer)))
:match-func (lambda (msg)
(when msg
(or (mu4e-message-contact-field-matches msg :to "jherrlin@gmail.com")
(mu4e-message-contact-field-matches msg :from "jherrlin@gmail.com")
(mu4e-message-contact-field-matches msg :cc "jherrlin@gmail.com")
(mu4e-message-contact-field-matches msg :bcc "jherrlin@gmail.com")
(string-match-p "^/gmail/Inbox" (mu4e-message-field msg :maildir)))))
:vars '( ( user-mail-address . "jherrlin@gmail.com" )
( smtpmail-smtp-user . "jherrlin@gmail.com" )
( mu4e-compose-signature . "Mvh John" )
( smtpmail-smtp-server . "smtp.gmail.com" )
( smtpmail-smtp-service . 587 )
( mu4e-maildir-shortcuts . ((:maildir "/gmail/Inbox" :key ?i)))
( mu4e-bookmarks
.
(( :name "Unread messages"
:query "maildir:/gmail/Inbox AND flag:unread AND NOT flag:trashed AND NOT outdoorexperten"
:key ?u)
( :name "Today's messages"
:query "maildir:/gmail/Inbox AND date:today..now"
:key ?t)
( :name "Last 7 days"
:query "maildir:/gmail/Inbox AND date:7d..now"
:hide-unread t
:key ?w)
( :name "Deleted"
:query "flag:trashed"
:key ?d)
( :name "Possibly garbage"
:query "bokio OR outdoorexperten"
:key ?g)))))
,(make-mu4e-context
:name "school"
:enter-func (lambda ()
(mu4e-message "Entering school context")
(when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
(revert-buffer)))
:leave-func (lambda ()
(mu4e-message "Leaving school context")
(when (string-match-p (buffer-name (current-buffer)) "mu4e-main")
(revert-buffer)))
:match-func (lambda (msg)
(when msg
(or (mu4e-message-contact-field-matches msg :to "jh222jx@student.lnu.se")
(mu4e-message-contact-field-matches msg :from "jh222jx@student.lnu.se")
(mu4e-message-contact-field-matches msg :cc "jh222jx@student.lnu.se")
(mu4e-message-contact-field-matches msg :bcc "jh222jx@student.lnu.se"))))
:vars '( ( user-mail-address . "jh222jx@student.lnu.se" )
( smtpmail-smtp-user . "jh222jx@student.lnu.se" )
( smtpmail-smtp-server . "smtp.gmail.com" )
( smtpmail-smtp-service . 587 )
( mu4e-compose-signature . "Mvh John" )
( mu4e-maildir-shortcuts . ((:maildir "/lnu/Inbox" :key ?i)))
( mu4e-bookmarks
.
(( :name "All school mails"
:query "maildir:/lnu/Inbox"
:key ?a)
( :name "Unread school messages"
:query "maildir:/lnu/Inbox AND flag:unread AND NOT flag:trashed"
:key ?u)))))))
#+end_src
This is the structure of the smtp credentials file.
#+BEGIN_SRC shell :results output code
gpg --decrypt ~/.password-store/smtp.gmail.com/jherrlin@gmail.com.gpg
#+END_SRC
#+RESULTS:
#+begin_src shell
<PASSWORD>
user: jherrlin@gmail.com
port: 587
host: smtp.gmail.com
#+end_src