Offlineimap
Offlineimap is a program that allows you to sync between an external imap server, and a local maildir folder. This allows you to read your local inbox locally, and quickly (even if you do not have the internet).
Documentation
commented offlineimap.conf https://github.com/OfflineIMAP/offlineimap/blob/master/offlineimap.conf official docs https://www.offlineimap.org/documentation.html man page https://www.offlineimap.org/doc/offlineimap.html github https://github.com/OfflineIMAP/offlineimap3
Locations
~/.offlineimaprc
offlineimap config file ~/.offlineimap.py
python functions/classes defined here can be accessed in .offlineimaprc (for nametrans, folderfilter, ... )
Install
sudo pacman -S offlineimap python2-pysqlite
Usage
offlineimap # sync all mailboxes offlineimap -a junk,work # sync only junk,work mailboxes offlineimap --info # test/debug folderfilter/nametrans settings without copying data!You'll likely want to add it to your crontab, or create a systemd timer for it (better).
# offlineimap can be run from the commandline, # but you'll likely want to stick it in your crontab */5 * * * * offlineimap -q ## quick sync */30 * * * * offlineimap ## in-depth sync
Configuration
General
This section has general settings shared by all mailboxes.
# ~/.offlineimaprc # vim: ft=dosini [general] ui = ttyui pythonfile = ~/.offlineimap.py # any functions/classes defined here can be called in .offlineimaprc accounts = work, junk, pers, mfw [mbnames] filename = ~/.mutt/mailboxes header = "mailboxes " peritem = "+%(accountname)s/%(foldername)s" sep = "/" footer = "\n"Accounts
Here we'll configure the email accounts that get managed by offlineimap.
The basic concept for offlineimap is defining two repositories, then connecting them in an account.
Everything is then synchronized between the two accounts.
You may define as many accounts or repositories as you'd like.
Login Auth
# ~/.offlineimaprc # ..general settings.. [Account work] localrepository = work-local remoterepository = work-remote [Repository work-local] type = Maildir localfolders = ~/.mail/work #folderfilter = lambda foldername: foldername not in ('[Gmail].All Mail', '[Gmail].Sent Mail', '[Gmail].Trash') #folderfilter = lambda folder: folder in ('INBOX','Drafts','Sent') maxconnections = 3 [Repository work-remote] ssl = yes type = Gmail remoteuser = willjpittman@gmail.com remotepass = <password> # OR remotepasseval (python from ~/.offlineimap.py) realdelete = no maxconnections = 3 sslcacertfile = /etc/ssl/certs/ca-certificates.crtMailctl GMail OAUTH
mailctl can obtain and renew OAUTH2 tokens for other programs.
NOTE:
I also needed to modify
/usr/lib/python3.10/site-packages/offlineimap/repository/IMAP.py
to convert bytestrings to strs.def getoauth2_client_id(self): # ... if isinstance(client_id, bytes): client_id = client_id.decode() def getoauth2_client_secret(self): # ... if isinstance(client_secret, bytes): client_secret = client_secret.decode()
# ~/.offlineimaprc [general] pythonfile = ~/.offlineimap.py [Repository foo-remote] # ... auth_mechanisms = XOAUTH2 oauth2_client_id = <YOUR_OAUTH2_CLIENT_ID> oauth2_client_secret = <YOUR_OAUTH2_CLIENT_SECRET> oauth2_request_url = https://accounts.google.com/o/oauth2/token oauth2_access_token_eval = get_token("<YOUR_EMAIL_ADDRESS_FOR_THIS_ACCOUNT>")# ~/.offlineimap.py import subprocess def get_token(email_address): cmd = subprocess.run(["mailctl", "access", "%s" % email_address], capture_output=True) return cmd.stdout.decode()Gmail OAUTH2
NOTE:
this uses an OAUTH2 token, but does not renew it (bad)
Generate OAUTH2 Token
See gmail
Follow Authentication/OAUTH2 instructions to retrieve refresh token.
Download a copy of oauth2 script
- download script: https://github.com/google/gmail-oauth2-tools/blob/master/python/oauth2.py
- save to
~/.mutt/scripts/oauth2.py
~/.offlineimaprc
# ... identical to LOGIN auth settings # plaintext within file [Repository work-remote] auth_mechanisms = XOAUTH2 oauth2_client_id = <your-clientid> oauth2_client_secret = <your-secrete> oauth2_request_url = https://accounts.google.com/o/oauth2/token oauth2_refresh_token = <your-refresh-token> # eval command to get files #oauth2_client_id_eval = get_client_id("accountname") #oauth2_client_secret_eval = get_client_secret("accountname") #oauth2_refresh_token_eval = get_refresh_token("accountname")
pythonfile
The
pythonfile =
option allows you to define python callables
you can invoke to obtain configuration values.# ~/.offlineimaprc [general] pythonfile = ~/.offlineimap.py [Repository pers-remote] # ... remotepasseval = 'get_password()'#!/usr/bin/env python # ~/.offlineimap.py def get_password(): return 'password'