Skip to content

Instantly share code, notes, and snippets.

@TohidEq
Last active December 24, 2025 10:24
Show Gist options
  • Select an option

  • Save TohidEq/2c9cce7735c914d27b430a37c43229d8 to your computer and use it in GitHub Desktop.

Select an option

Save TohidEq/2c9cce7735c914d27b430a37c43229d8 to your computer and use it in GitHub Desktop.
Setting Up Multiple Gmail Accounts in Doom Emacs (mbsync + mu4e, App Password)

Gmail in Doom Emacs using mbsync ,mu4e and App Password(not OAuth2)

A personal note documenting how I set up multiple Gmail accounts in Doom Emacs using App Passwords (not OAuth2), mbsync, and mu4e.

example

Components covered:

  • Doom Emacs
  • Gmail App Password (no OAuth2)
  • mbsync (isync) for local IMAP sync
  • mu4e

Read This.

  • Remember:

    press c : lowercase c : c

    press C : uppercase C : shift + c

    C-c : control+c

    M-x : alt+x


0. Installing Stuff

0.0. Remove any doom or emacs folders.

mv -r ~/.emacs.d ~/.emacs.d-backup
mv -r ~/.emacs ~/.emacs-backup
mv -r ~/.doom.d ~/.doom.d-backup
mv -r ~/.emacs ~/.emacs-backup

mv -r ~/.config/.emacs.d ~/.config/.emacs.d-backup
mv -r ~/.config/.emacs ~/.config/.emacs-backup
mv -r ~/.config/.doom.d ~/.config/.doom.d-backup
mv -r ~/.config/.emacs ~/.config/.emacs-backup

0.1. Install Doom Emacs

git clone --depth 1 https://github.com/doomemacs/doomemacs ~/.config/emacs
~/.config/emacs/bin/doom install
  • Also add $HOME/.config/emacs/bin/ to your paths:
  • I use fish so just: fish_add_path $HOME/.config/emacs/bin
  • Using bash: add export PATH="$HOME/.config/emacs/bin:$PATH" to ~/.bashrc

0.2. Install configs stuffs

  • mu
  • isync
  • msmtp
  • mbsync

Using yay? Nice, JUST RUN: yay -S mu isync msmtp mbsync

  • DONE.

1. Setting Up App Passwords

1.1. Create n app passwords for your n gmail accounts and save them to some files like these:

  • IMAGINE:

account 1 gmail: acc1@gmail.com

account 1 app passowrd : abcd efgh ijkl

account 1 gmail: acc2@gmail.com

account 2 app passowrd : aaaa bbbb cccc dddd

  • THEN:

  • for each acc:

    • this example is for acc1
    • Go to a secret directory and create .mbsyncpass-acc1 and put its password (abcd efgh ijkl) into it.
    • run >> gpg2 -c .mbsyncpass-acc1 . it will ask you a new password to encrypt file, !! REMEMBER IT !! ⚠️.

    it will create a new encrypted file (.mbsyncpass-acc1.gpg),

    • remove .mbsyncpass-acc1 file

    • -- > > > undo? : >> $ gpg2 -d .mybsyncpass-acc1.gpg>.mbsyncpass-acc1

  • THEN:

1.2. Run Doom Emacs and create new empty buffer(space b N)

  • Write n lines for your n accounts:
machine smtp.gmail.com port 587 login Acc1@gmail.com password "abcd efgh ijkl"
machine smtp.gmail.com port 587 login Acc2@gmail.com password "aaaa bbbb cccc dddd"
  • Save: press (space f s) to save> write ~/authinfo.gpg > enter > it will ask you a new passowrd to encrypt file, !! REMEMBER IT !! ⚠️.

  • DONE.


2. Prepare Doom Emacs

  • Open Doom Emacs
  • Press (space f p)
  • Select init.el
  • Enter
  • Find
       ;;(mu4e +org +gmail)
  • Uncomment it (remove ;;):
      (mu4e +org +gmail)
  • Save it and exit :wq or (space f s)

  • DONE.


3. .mbsyncrc

3.0 Prepare some folders for emails

  • IMAGINE:

You chose /home/me/here/there/mails/ to store your mails

create it with: mkdir -p /home/me/here/there/mails/

3.1. Go to another secret directory and create .mbsyncrc file

3.2 Paste these to .mbsyncrc:

  • ⚠️ Replace any [USER_A] to your email name like: acc1

careful ; [[USER_A]] will be [acc1]

  • ⚠️ Replace any path/to/[USER_A]-gmail/ with your owns (for each acc)

  • ⚠️ Replace any path/to/.mbsyncpass-[USER_A].gpg with your owns (for each acc)

# mbsyncrc based on
# http://www.ict4g.net/adolfo/notes/2014/12/27/EmacsIMAP.html
# ACCOUNT INFORMATION
IMAPAccount [USER_A]-gmail
# Address to connect to

#  ! ! ! ! ! ! ! ! ! ! !
# [USER_A]   ==> MyName
# [[USER_A]] ==> [MyName]
#  ! ! ! ! ! ! ! ! ! ! !

Host imap.gmail.com
User [USER_A]@gmail.com
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d path/to/.mbsyncpass-[USER_A].gpg"
AuthMechs PLAIN
TLSType IMAPS
TLSVersions +1.2 +1.3
CertificateFile /etc/ssl/certs/ca-certificates.crt
# THEN WE SPECIFY THE LOCAL AND REMOTE STORAGE
# - THE REMOTE STORAGE IS WHERE WE GET THE MAIL FROM (E.G., THE
#   SPECIFICATION OF AN IMAP ACCOUNT)
# - THE LOCAL STORAGE IS WHERE WE STORE THE EMAIL ON OUR COMPUTER
# REMOTE STORAGE (USE THE IMAP ACCOUNT SPECIFIED ABOVE)
IMAPStore [USER_A]-gmail-remote
Account [USER_A]-gmail
# LOCAL STORAGE (CREATE DIRECTORIES with mkdir -p ~/Maildir/[USER_A]-gmail)
MaildirStore [USER_A]-gmail-local
Path path/to/[USER_A]-gmail/
Inbox path/to/[USER_A]-gmail/INBOX
# REQUIRED ONLY IF YOU WANT TO DOWNLOAD ALL SUBFOLDERS; SYNCING SLOWS DOWN
# SubFolders Verbatim
# CONNECTIONS SPECIFY LINKS BETWEEN REMOTE AND LOCAL FOLDERS
#
# CONNECTIONS ARE SPECIFIED USING PATTERNS, WHICH MATCH REMOTE MAIl
# FOLDERS. SOME COMMONLY USED PATTERS INCLUDE:
#
# 1 "*" TO MATCH EVERYTHING
# 2 "!DIR" TO EXCLUDE "DIR"
# 3 "DIR" TO MATCH DIR
Channel [USER_A]-gmail-inbox
Far :[USER_A]-gmail-remote:
Near :[USER_A]-gmail-local:
Patterns INBOX
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
Channel [USER_A]-gmail-trash
Far :[USER_A]-gmail-remote:"[Gmail]/Trash"
Near :[USER_A]-gmail-local:"[[USER_A]].Trash"
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
Channel [USER_A]-gmail-sent
Far :[USER_A]-gmail-remote:"[Gmail]/Sent Mail"
Near :[USER_A]-gmail-local:"[[USER_A]].Sent Mail"
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
#
# Channel [USER_A]-gmail-all
# Far :[USER_A]-gmail-remote:"[Gmail]/All Mail"
# Near :[USER_A]-gmail-local:"[[USER_A]].All Mail"
# Create Both
# Expunge Both
# SyncState *
# MaxMessages 600
# ExpireUnread yes
# Channel [USER_A]-gmail-starred
# Far :[USER_A]-gmail-remote:"[Gmail]/Starred"
# Near :[USER_A]-gmail-local:"[[USER_A]].Starred"
# Create Both
# Expunge Both
# SyncState *
# MaxMessages 600
# ExpireUnread yes
# GROUPS PUT TOGETHER CHANNELS, SO THAT WE CAN INVOKE
# MBSYNC ON A GROUP TO SYNC ALL CHANNELS
#
# FOR INSTANCE: "mbsync gmail" GETS MAIL FROM
# "gmail-inbox", "gmail-sent", and "gmail-trash"
#
Group [USER_A]-gmail
Channel [USER_A]-gmail-inbox
Channel [USER_A]-gmail-sent
Channel [USER_A]-gmail-trash
# Channel [USER_A]-gmail-all
# Channel [USER_A]-gmail-starred
# ================================================================================
#
# ACCOUNT INFORMATION
IMAPAccount [USER_B]-gmail
# Address to connect to
Host imap.gmail.com
User [USER_B]@gmail.com
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d path/to/.mbsyncpass-[USER_B].gpg"
AuthMechs PLAIN
TLSType IMAPS
TLSVersions +1.2 +1.3
CertificateFile /etc/ssl/certs/ca-certificates.crt
# THEN WE SPECIFY THE LOCAL AND REMOTE STORAGE
# - THE REMOTE STORAGE IS WHERE WE GET THE MAIL FROM (E.G., THE
#   SPECIFICATION OF AN IMAP ACCOUNT)
# - THE LOCAL STORAGE IS WHERE WE STORE THE EMAIL ON OUR COMPUTER
# REMOTE STORAGE (USE THE IMAP ACCOUNT SPECIFIED ABOVE)
IMAPStore [USER_B]-gmail-remote
Account [USER_B]-gmail
# LOCAL STORAGE (CREATE DIRECTORIES with mkdir -p ~/Maildir/[USER_B]-gmail)
MaildirStore [USER_B]-gmail-local
Path path/to/[USER_B]-gmail/
Inbox path/to/[USER_B]-gmail/INBOX
# CONNECTIONS SPECIFY LINKS BETWEEN REMOTE AND LOCAL FOLDERS
#
# CONNECTIONS ARE SPECIFIED USING PATTERNS, WHICH MATCH REMOTE MAIl
# FOLDERS. SOME COMMONLY USED PATTERS INCLUDE:
#
# 1 "*" TO MATCH EVERYTHING
# 2 "!DIR" TO EXCLUDE "DIR"
# 3 "DIR" TO MATCH DIR
Channel [USER_B]-gmail-inbox
Far :[USER_B]-gmail-remote:
Near :[USER_B]-gmail-local:
Patterns INBOX
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
Channel [USER_B]-gmail-trash
Far :[USER_B]-gmail-remote:"[Gmail]/Trash"
Near :[USER_B]-gmail-local:"[[USER_B]].Trash"
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
Channel [USER_B]-gmail-sent
Far :[USER_B]-gmail-remote:"[Gmail]/Sent Mail"
Near :[USER_B]-gmail-local:"[[USER_B]].Sent Mail"
Create Both
Expunge Both
SyncState *
MaxMessages 600
ExpireUnread yes
#
# Channel [USER_B]-gmail-all
# Far :[USER_B]-gmail-remote:"[Gmail]/All Mail"
# Near :[USER_B]-gmail-local:"[[USER_B]].All Mail"
# Create Both
# Expunge Both
# SyncState *
# MaxMessages 600
# ExpireUnread yes
#
# Channel [USER_B]-gmail-starred
# Far :[USER_B]-gmail-remote:"[Gmail]/Starred"
# Near :[USER_B]-gmail-local:"[[USER_B]].Starred"
# Create Both
# Expunge Both
# SyncState *
# MaxMessages 600
# ExpireUnread yes
# GROUPS PUT TOGETHER CHANNELS, SO THAT WE CAN INVOKE
# MBSYNC ON A GROUP TO SYNC ALL CHANNELS
#
# FOR INSTANCE: "mbsync gmail" GETS MAIL FROM
# "gmail-inbox", "gmail-sent", and "gmail-trash"
#
Group [USER_B]-gmail
Channel [USER_B]-gmail-inbox
Channel [USER_B]-gmail-sent
Channel [USER_B]-gmail-trash
#Channel [USER_B]-gmail-all
#Channel [USER_B]-gmail-starred

You can uncomment any section you want. Just remember to uncomment the related channels too.

  • DONE.

4. Doom Emacs Config

4.0. Open Doom emacs

4.1. (space f o)

4.2. Select config.el then press Enter

4.3. Paste:

  • ⚠️ Replace ~/path/to/mail/ , ~/path/to/.mbsyncrc with your own
  • ⚠️ Replace account1, account2 with our own (for each acc)
;;; email.el -*- lexical-binding: t; -*-

(use-package! mu4e
  :commands mu4e
  :config
  ;; Maildir root (where mbsync puts emails)
  (setq mu4e-root-maildir "~/path/to/mail")
  ;; Use mbsync with your specific config
  (setq mu4e-get-mail-command "mbsync -c ~/path/to/.mbsyncrc -a")
  ;; Automatically pick the first context if multiple (optional)
  (setq mu4e-context-policy 'pick-first)

  ;; Define contexts for two accounts
  (setq mu4e-contexts
        `(,(make-mu4e-context
             :name "Account1"
             :match-func (lambda (msg)
                           (when msg
                             (string-prefix-p "/account1" (mu4e-message-field msg :maildir))))
             :vars '((user-mail-address      . "account1@gmail.com")
                     (user-full-name        . "Account One")
                     (mu4e-sent-folder      . "/account1/[account1].Sent")
                     (mu4e-drafts-folder    . "/account1/[account1].Drafts")
                     (mu4e-trash-folder     . "/account1/[account1].Trash")
                     (mu4e-refile-folder    . "/account1/[account1].All Mail")
                     (smtpmail-smtp-server  . "smtp.gmail.com")
                     (smtpmail-smtp-service . 587)
                     (smtpmail-stream-type  . starttls)))

          ,(make-mu4e-context
             :name "Account2"
             :match-func (lambda (msg)
                           (when msg
                             (string-prefix-p "/account2" (mu4e-message-field msg :maildir))))
             :vars '((user-mail-address      . "account2@gmail.com")
                     (user-full-name        . "Account Two")
                     (mu4e-sent-folder      . "/account2/[account2].Sent")
                     (mu4e-drafts-folder    . "/account2/[account2].Drafts")
                     (mu4e-trash-folder     . "/account2/[account2].Trash")
                     (mu4e-refile-folder    . "/account2/[account2].All Mail")
                     (smtpmail-smtp-server  . "smtp.gmail.com")
                     (smtpmail-smtp-service . 587)
                     (smtpmail-stream-type  . starttls))))))


(setq message-send-mail-function 'message-smtpmail-send-it
      smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587
      smtpmail-stream-type 'starttls
      smtpmail-auth-supported '(login plain)
      smtpmail-debug-info nil
      smtpmail-debug-verbose nil)


;; Keybinding to open mu4e quickly
(map! :leader
      :desc "Open Mail (mu4e)"
      "o m" #'mu4e)
  • Tip:

    You can make another file in your doom config dir like ~/.config/doom/here/there/mail.el and then link it to config.el with:

    (load! "here/there/mail") ;; no need ".el" at the end

4.4 Open a terminal and appy settings by running doom sync or ~/.config/emacs/bin/doom sync

  • DONE.

5. Getting My Emails

5.0. Open a terminal

5.1. Run (getting mails)

  • The -V is to see (what's going on), you can remove it if u like less texts.
mbsync -c ~/myworld/secret/emacsSecrets/mu4e/.mbsyncrc -a -V    
  • It will ask you your password for every account
  • you can use account1-gmail instead of -a to get mails jsut for one acc

5.2. Run (indexing, faster search)

  • ⚠️ Replace the path with our own mail directory path
mu init --maildir /home/me/there/here/mail

mu index --lazy-check
  • DONE.

6. OPEN EMACS TO SEE YOUR MAILS

6.0. Open Doom Emacs

6.1. Press (space o m) to open mail menu

6.2. Press J and TAMAM. q : Exit

  • DONE

7. Sending Some Emails

7.0. Open Doom Emacs

7.1. Press (space o m) to open mail menu

7.1. Press (;) to Switch Account and select your acc

7.3 Press (C) to create new mail

7.4 Write yor mail

7.5 Send it with Pressing (C-c C-c) == (control + c control + c)

  • It will ask you your passowrd for ~/.authinfo.gpg file.

  • DONE.


8. Syncing Gmail in Emacs

8.0. Open Doom Emacs

8.1. Press (space o m) to open mail menu

8.2 Press (u) and enter password

8.3 Wait Wait Wait

8.4 Press (M-x) == (alt + x)

8.5 Search for mu4e-update-index or mu4e-update-index-nonlazy

8.6 Enter and Wait and Done

  • DONE.

@sarg
Copy link

sarg commented Dec 24, 2025

oauth2 is pretty simple with oama:
~/.config/oama/config.yaml

encryption:
    tag: GPG
    contents: '0xYOURGPGKEY'

services:
  google:
    client_id: '406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com'
    client_secret: 'kSmqreRr0qwBWJgbf5Y-PjSU' # thunderbird

~/.config/msmtp/config - passwordeval oama access your.account@gmail.com
~/.config/isyncrc

IMAPStore gmail-remote
    Host imap.gmail.com
    User your.account@gmail.com
    PassCmd "oama access your.account@gmail.com"
    AuthMechs XOAUTH2
    TLSType IMAPS
    TLSVersions +1.3
    CertificateFile /etc/ssl/certs/ca-certificates.crt

you'll need to do oama authorize google your.account@gmail.com once to obtain the token, later on oama would refresh the token automatically

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment