Use multiple gmail accounts via mutt and (offline) IMAP

I started with a new project recently, which means I have to use yet another Google Workspace (i.e. gmail for businesses). While having the gmail webapp open in multiple Firefox Multi-Account Containers is an option, it's not something I like to do. And I don't really like the gmail web interface anyway. I prefer mutt (and use it since forever,,,). Some years ago I sort of managed to read gmail mails via IMAP, but couldn't get sending to work. So I decided to give this another try. And it worked!

Overview

  • I have multiple separate gmail accounts
  • I use mutt to read and write email
  • I use offlineimap to download mails via IMAP onto my laptop (so I can read my mails while offline, and search through them on my disk)
  • To send mails, I drop them into an exim running on my laptop, which then sends them via the mail service I use
    • This did not work for gmail, but I found something that works (see below)

Syncing gmail via offlineimap and an "app password"

This seems rather easy, but google does not really like you to use your regular password in automated tools. One solution is to use OAuth2, as described here. But this seems a bit to much hassle, so I choose the other route, i.e. setting up an "app password". An "app password" is a password that google generates for you so you can use it in various apps (of dubious security).

To get such an app password, you first have to secure your account with Two Factor Authentication (2FA) (if you haven't already done that):

  • Go to https://myaccount.google.com
  • Find "2-Step Verification" under the Security headline
  • Go through the process. I use the "Google Authenticator" app on my mobile phone
  • After you've set this up, you'll find the new option "App passwords" under "Security" / "Signing into Google"
  • Select an app ("Mail") and give it a custom name (eg "offlineimap"), click on "generate" and copy the password (you'll never see it again!)

Now you can add a new Account to your .offlineimaprc:

[Account FOO]
localrepository = LocalFoo
remoterepository = RemoteFoo
synclabels = yes

[Repository LocalFoo]
type = Maildir
localfolders = /path/to/mails/Foo

[Repository RemoteFoo]
type = IMAP
remotehost = imap.gmail.com
# if you have a custom domain set up:
remoteuser = foo@example.com
# if you use a plain gmail account:
# remoteuser = foo@gmail.com
remotepass = your-app-password
ssl = yes
sslcacertfile = /etc/ssl/certs/ca-certificates.crt

Before you run offlineimap you might want to consider configuring your gmail labels (i.e. what google uses for mail folders). Google sets up a bunch of (IMO stupid) default labels. It will also duplicate mails, because all mails stay in the Inbox and will be sort-of-copied into folders (if the label matches). So go to your gmail settings (click on the gear-wheel, then "See all settings"), go to "Labels" and uncheck the "Show in IMAP" box on all labels (except Inbox, which you cannot uncheck anyway..). If you have set up mail filters, make sure they have the "Skip Inbox" flag set, otherwise you'll get them twice.

Now is also a good time to clean up your Inbox (or you'll wait a long time on the first sync..)

Configuring mutt

The first thing we need to do is to tell mutt about the new folder / labels / mailboxes (in mutt language..):

+mailboxes =Foo/INBOX +Foo/'[Gmail].Sent Mail' +Foo/some_label

Foo here is the actual directory name of the maildir you specified in offlineimap: localfolders = /path/to/mails/Foo. You can list all the labels you enabled for IMAP here, and mutt will automatically jump to the mail folder if there is new mail after an offlineimap run.

Another thing I like to do is to set up a separate "profile" for each account, using a different color and sender for each project. For this I set up a file like this in my ~/.mutt/:

# file: ~/.mutt/profile_foo
set from="Thomas Klausner <domm@example.net>"
set use_from
set envelope_from
set signature=~/.foo_signature
color indicator black brightgreen

This will make sure I use the right sender, and will also alert me as who I am currently writing by setting the indicator to a specific color.

But how do we enable this profile? Via a folder-hook:

folder-hook =Foo "source ~/.mutt/profile_foo\n"

Anytime we enter a folder under Foo, we source this profile. Nice!

Sending mail

But how can we now actually send mail using the gmail sender? Thanks to spammers, you cannot just use any sender address with any SMTP server anymore, they are much stricter now (and gmail even more so). So we need to send mails via gmail, using the correct set of credentials. I assume that exim has some setting to do this, but I found an easier way:

Mutt can send mail not only via localhost, but also directly via SMTP!

All we have to do is add something like this to our ~/.mutt/profile_foo

set smtp_url = "smtps://foo@example.com:your-app-password@smtp.gmail.com:465"

And we also need to unset smtp_url for the default account (which uses the local exim). So in the default_profile just add unset smtp_url. And load the default profile via another folder hook:

folder-hook . "source ~/.mutt/profile_default\n"

And that's how I prevented going crazy having to juggle multiple gmail accounts!

One downside of this approach is that the app passwords are now lying around on my disk, so anybody with access to my disk can read/send mails. In case I know my disk has been compromised, I could disable the app passwords in my google account settings. But a nicer approach would be to store them in some password store (I use gopass) and somehow inject them after unlocking them. This will have to wait for another time...