Send and Receive outlook email in WSL2 Emacs with mu4e, offlineimap and gnugpg
I’ve tried many times to enable mu4e and offlineimap in msys2 environment, but no result. Although the author of mu4e provides the unofficial package files for msys2, but I still get a compile failure. Worse off, offlineimap is not working in msys2 environment.
I’ve configured emacs under WSL2 and I feel little difference from msys2 mingw64 emacs. And It is also quite easy to configure mu4e and offlineimap for Manjaro.
This guide will lead you to configure mu4e and offlineimap in emacs, and securely encrypt the email credentials.
1. install
Supposing you have configured Manjaro WSL2 and then open Manjaro WSL2 shell:
# install pip sudo pacman -S python-pip # install python gpg sudo pip install python-gnupg getpass4 # offlineimap sudo pacman -S offlineimap # mu4e wget https://github.com/djcb/mu/archive/1.6.10.tar.gz tar zxvf 1.6.10.tar.gz cd mu-1.6.10 ./augogen.sh make sudo make install
2. configure Emacs
Emacs config extracted from my .emacs:
;; get load path (eval-and-compile (defun mu4e-load-path () (cond ((eq system-type 'darwin) "/usr/local/Cellar/mu/1.0_1/share/emacs/site-lisp/mu/mu4e") ((eq system-type 'windows-nt) "/usr/local/share/emacs/site-lisp/mu4e") ((eq system-type 'gnu/linux) "/usr/local/share/emacs/site-lisp/mu4e/")))) (use-package mu4e :ensure nil :functions (mu4e-compose-reply mu4e~view-quit-buffer) :defines (mu4e-html2text-command mu4e-mu-binary mu4e-get-mail-command mu4e-update-interval mu4e-hide-index-messages mu4e-use-fancy-chars mu4e-view-show-images mu4e-view-fields mu4e-headers-fields mu4e-compose-cite-function mu4e-compose-reply-recipients mu4e-headers-mode-map mu4e-compose-mode-map mu4e-view-mode-map shr-color-visible-luminance-min shr-color-visible-distance-min) :custom (mu4e-compose-reply-recipients 'sender) (mu4e-compose-signature-auto-include nil) (mu4e-index-update-in-background nil) ;; prompt for gpg passwd :commands (mu4e mu4e-compose-new) :load-path (lambda () (list (mu4e-load-path))) :config (require 'sendmail) ;; turn html email to lighter color in dark theme (require 'mu4e-contrib) (setq mu4e-html2text-command 'mu4e-shr2text) (setq shr-color-visible-luminance-min 60) (setq shr-color-visible-distance-min 5) (setq shr-use-colors nil) (advice-add #'shr-colorize-region :around (defun shr-no-colourise-region (&rest ignore))) (require 'org-mu4e) ;; capture link (add-to-list 'Info-additional-directory-list "/usr/local/share/info") (setq mu4e-mu-binary "/usr/local/bin/mu") (setq mail-user-agent 'mu4e-user-agent) ;; Fetch mail by offlineimap (setq mu4e-get-mail-command "offlineimap -c ~/.offlineimaprc -u quiet") ;; Fetch mail in 60 sec interval (setq mu4e-update-interval 300) ;; hide indexing messages from minibuffer (setq mu4e-hide-index-messages t) (setq mu4e-use-fancy-chars nil) (setq mu4e-view-show-images t) ;; configure view fields (setq mu4e-view-fields '(:subject :from :to :cc :date :mailing-list :attachments :signature :decryption)) (setq mu4e-headers-fields '( (:human-date . 12) (:flags . 6) (:from . 22) (:subject . nil))) (setq mu4e-compose-cite-function 'mu-cite-original) (add-hook 'mu4e-view-mode-hook 'visual-line-mode) (add-hook 'mu4e-compose-mode-hook 'orgalist-mode) (add-hook 'mu4e-compose-mode-hook (lambda () (auto-fill-mode -1))) ;; setup shortcuts (setq mu4e-maildir-shortcuts '( ("/outlook/Inbox" . ?i) ("/outlook/Sent" . ?s))) ;; smtp send settings (setq send-mail-function 'smtpmail-send-it smtpmail-stream-type 'starttls smtpmail-smtp-service 587))
3. add .offlineimaprc
create ~/.offlineimaprc
replace _your_email_
with your email address
(for example: kimim@outlook.com ):
[general] accounts = outlook maxsyncaccounts = 3 pythonfile = ~/passwd_prompt.py [Account outlook] localrepository = outlook-Local remoterepository = outlook-Remote utf8foldernames = True [Repository outlook-Local] type = Maildir localfolders = ~/.mail/outlook [Repository outlook-Remote] type = IMAP remotehost = imap.outlook.com remoteuser = _your_email_ remotepasseval = get_authinfo_password() ssl = true sslcacertfile = /etc/ssl/cert.pem maxconnections = 4 realdelete = yes
4. add python password prompt script
create ~/passwd_prompt.py
(copied from Seth Kenlon):
#!/usr/bin/env python # by Seth Kenlon # GPLv3 import os import gnupg import getpass from pathlib import Path def get_api_pass(): homedir = str(Path.home()) gpg = gnupg.GPG(gnupghome=os.path.join(homedir, ".gnupg"), use_agent=True) passwd = getpass.getpass(prompt="Remote: Enter password: ", stream=None) with open(os.path.join(homedir, 'pass.gpg'), 'rb') as f: apipass = (gpg.decrypt_file(f, passphrase=passwd)) f.close() return str(apipass) def get_authinfo_password(): authinfo = os.popen("gpg -q --no-tty -d ~/pass.gpg").read() return authinfo if __name__ == "__main__": apipass = get_api_pass() print(apipass) apipass = get_authinfo_password() print(apipass)
If you use get_api_pass()
inside .offlineimaprc
, you can enable
password prompt filter. It is important to set the prompt in above
code as “Remote: Enter password: ”, because it is used by mu4e to
trigger emacs to ask for password:
(defvar mu4e~get-mail-password-regexp "^Remote: Enter password: $" "Regexp to match a password query in the `mu4e-get-mail-command' output.")
If you use get_authinfo_password()
, the password extraction is done by
gpg
, thus you do not need to add above emacs configuration. This function is borrowed from Gábor Melis.
5. add encrypted password file: pass.gpg
Use emacs to find a new file ~/pass.gpg
, type in your password, and
save with master password protection.
6. add smtp send credentials: .authinfo.gpg
Use emacs to find a new file ~/.authoinfo.gpg
, type in following line:
machine smtp.outlook.com login _your_email_ port 587 password _your_passwd_
Replace _your_email_
with your email address, and replace
_your_passwd_
with your password.
7. download email
Execute in Manjaro WSL2 shell:
cd ~
offlineimap
8. initialize mu4e
Initialize mu and index your emails:
mu init -m ~/.mail --my-address=_your_email_ mu index
Replace _your_email_
with your email address.
9. have a try
Now type M-x mu4e
, emacs will show mu4e dashboard for you. j i
will
show the inbox and C
will create a new email for you. You may need to
type the master password for sending and updating email. But your
email credential is not stored in file system as plain text.
10. Limitation
When mu4e triggers offlineimap to update email, you need to type in the master password for offlineimap password, because we cannot keep the password for each invoke of offlineimap.