Setting up multiple gmail accounts in Emacs
Table of Contents
Get a dummy password from Gmail
For your Gmail account do the following things first:
- Enable 2 step authentication
- Get an app password - This will help you to access your account without going through 2 step authentication. This can be deleted and regenerated when you think your account has been compromised.
Let's assume that the password generated was thisismysecretpw.
Generate GPG keys
This will be used to encrypt files containing sensitive information like
authinfo.gpg
which will be used to store the app password.
gpg --gen-key
Adding information to authinfo.gpg
If you have gpg keys then Emacs will take care of encryption and decryption when
you open any file with .gpg
extension. Add the following lines to your
~/authinfo.gpg
file.
machine smtp.gmail.com login mailid@gmail.com port 25 password thisismysecretpw machine imap.gmail.com login mailid@gmail.com port 993 password thisismysecretpw
The first line will be used to send mail and the second will be used to fetch new mail. If you have more accounts, just add similar lines for them too.
Fetching using mbsync
First install the package from official repos or build from source.
Create .mbsyncrc
IMAPAccount gmail-mailid Host imap.gmail.com User mailid@gmail.com PassCmd "gpg --for-your-eyes-only --no-tty -qd ~/.authinfo.gpg | grep imap.gmail.com | grep mailid | awk '{ for (i=1; i<NF; i++) { if ($i == \"password\") print $(i+1) } }'" # To store the password in an encrypted file use PassCmd instead of Pass # PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d ~/.mailpass.gpg" # Use SSL SSLType IMAPS # The following line should work. If get certificate errors, uncomment the two # following lines and read the "Troubleshooting" section. CertificateFile /etc/ssl/certs/ca-certificates.crt #CertificateFile ~/.cert/imap.gmail.com.pem #CertificateFile ~/.cert/Equifax_Secure_CA.pem IMAPStore gmail-mailid-remote Account gmail-mailid MaildirStore gmail-mailid-local Subfolders Verbatim # The trailing "/" is important Path ~/.mail/gmail/mailid/ Inbox ~/.mail/gmail/mailid/inbox Channel gmail-mailid-default Master :gmail-mailid-remote: Slave :gmail-mailid-local:Inbox Channel gmail-mailid-sent Master :gmail-mailid-remote:"[Gmail]/Sent Mail" slave :gmail-mailid-local:Sent Channel gmail-mailid-trash Master :gmail-mailid-remote:"[Gmail]/Trash" slave :gmail-mailid-local:Trash Channel gmail-mailid-archive Master :gmail-mailid-remote:"[Gmail]/All Mail" slave :gmail-mailid-local:All Channel gmail-mailid-junk Master :gmail-mailid-remote:"[Gmail]/Spam" slave :gmail-mailid-local:Junk # Automatically create missing mailboxes, both locally and on the server Create Both # Automatically delete messages on either side if they are found deleted on the other Expunge Both # Save the synchronization state files in the relevant directory SyncState *
If you have multiple accounts the above block can be repeated by just replacing
all mailid
instances with your second mail id.
Fetch your mail
To fetch all your mail just run
mbsync -a
Automate fetching (For Linux users)
Create ~/.config/systemd/user/mbsync.service
with the following contents:
[Unit] Description=Mailbox synchronization service [Service] Type=oneshot ExecStart=/usr/bin/mbsync -Va ExecStartPost=/usr/bin/notmuch new
Create ~/.config/systemd/user/mbsync.timer
with the following contents:
[Unit] Description=Mailbox synchronization timer [Timer] OnBootSec=2m OnUnitActiveSec=3m Unit=mbsync.service [Install] WantedBy=timers.target
Start and enable(will automatically run it after you log in) the service:
systemctl --user start mbsync.timer systemctl --user enable mbsync.timer
notmuch
to search your mails
Set it up
notmuch
When asked for mail directory, mention ~/.mail
which I used in my ~/.mbsyncrc
.
This directory has all my accounts so notmuch can index all of it.
Index new mail
notmuch new
Emacs configuration
Default user name to use when sending mail using C-x m
:
(setq user-mail-address "mailid@gmail.com" user-full-name "First Last")
Make sure Emacs always uses ~/.authinfo.gpg
:
(setq auth-sources (list (expand-file-name "~/.authinfo.gpg")))
I have used leaf
instead of use-package
as the author claims to get it merged
into core Emacs some day. Don't worry, its lightweight and makes it easy to port
existing use-package
configuration blocks.
(leaf message :hook (message-send-hook . compro/message/change-smtp-settings) :bind ((message-mode-map ("C-c <C-tab>" . compro/message/toggle-from-header))) :preface (defun compro/message/toggle-from-header () "Toggle between two mail address that I have." (interactive) (save-excursion (save-restriction (message-narrow-to-headers) (while (not (looking-at "From: ")) (message-next-header)) (let ((from (message-fetch-field "from"))) (search-forward from) (if (string-match-p (regexp-quote "mailid@gmail.com") from) (replace-match "First2 Last2 <mailid2@gmail.com>") (replace-match "First Last <mailid@gmail.com>")))))) (defun compro/message/change-smtp-settings () "Change any SMTP details according to the current From line. For me it was only `smtpmail-smtp-user'. Other cases include `smtpmail-default-smtp-server' or `smtpmail-smtp-service' which is not configured in my implementation. This function needs to be added to `message-send-hook' to change details before sending the message." (save-excursion (save-restriction (message-narrow-to-headers) (let* ((from-field (message-fetch-field "from")) (from-mailid (when from-field (cadr (mail-extract-address-components (message-fetch-field "from")))))) (if from-mailid (setq smtpmail-smtp-user from-mailid) (error "Can't fetch `From' field from message headers")))))) :init (setq message-alternative-emails (regexp-opt '("mailid@gmail.com" "mailid2@gmail.com")) message-send-mail-function 'smtpmail-send-it) ) (leaf smtpmail :init (setq smtpmail-smtp-service 25 smtpmail-default-smtp-server "smtp.gmail.com"))
While composing a message(using C-x m
) just press C-c C-tab
to toggle between
mail ids. This can be changed in the compro/message/toggle-from-header
function.
Notmuch configuration is a bit challenging as it doesn't provide a standard way to delete a message.
(leaf notmuch :ensure t :bind ((notmuch-search-mode-map ("d" . compro/notmuch/tag-as-deleted) ("<delchar>" . compro/notmuch/tag-as-deleted) ("u" . compro/notmuch/remove-deleted-tag) ("D" . compro/notmuch/remove-deleted-tag) ("f" . compro/notmuch/tag-as-flagged) ("F" . compro/notmuch/remove-flagged-tag))) :init (fset 'compro/notmuch/tag-as-deleted (kmacro-lambda-form [?+ ?d ?e ?l ?e ?t ?e ?d return] 0 "%d")) (fset 'compro/notmuch/remove-deleted-tag (kmacro-lambda-form [?- ?d ?e ?l ?e ?t ?e ?d return] 0 "%d")) (fset 'compro/notmuch/tag-as-flagged (kmacro-lambda-form [?+ ?f ?l ?a ?g ?g ?e ?d return] 0 "%d")) (fset 'compro/notmuch/remove-flagged-tag (kmacro-lambda-form [?- ?f ?l ?a ?g ?g ?e ?d return] 0 "%d")))
To delete a message first tag them using d
then run:
rm -f `notmuch search --output=files --exclude=false tag:deleted`
You can add this command to mbsync.service
(we created initially) to
automatically delete tagged mails before re-indexing every 3 minutes. So, the line:
ExecStartPost=/bin/sh -c "/usr/bin/notmuch search --output=files --exclude=false tag:deleted | /usr/bin/xargs /bin/rm -f"
should be added below:
ExecStartPost=/usr/bin/notmuch new
I recommend not deleting mail automatically as it might be a disaster when you tag the wrong mail. You can instead delete them when you have time to manually run the command.
To start searching you can use M-x notmuch
:) That's all.