You are a happy Mutt user, and have been for while. When you have a stable internet connection, such as in the office, Mutt is a pleasure to use. However, when there is no active internet connection, Mutt does not work well if you store all your email online. This is a guide to use Mutt offline, syncing all data when the internet connection is available again.

This guide is based primarily on this guide, with a few sprinkles from this one and this other one added in. Note that many of the scripts and configuration files on this page are based on the ones at those links. Don’t reuse them without permission from these authors as well.

Tools used

  • offlineimap, to download and sync your email collection
  • notmuch, to index your email and make it searchable
  • msmtp, to postpone submission of emails you send

Prerequisites

I assume you have a mail server that is reachable via IMAP over TLS. I furthermore assume you submit email via a server to which you authenticate. The guide should be easy to modify to your situation.

Step 0: Configure mutt

First, change your .muttrc to point to a local maildir and MTA. Add or change the following:

set sendmail="~/bin/msmtp-enqueue.sh"
set spoolfile="~/Maildir/INBOX"
set folder="~/Maildir"
set record="~/Maildir/Sent"
set postponed="~/Maildir/Drafts"
set mbox_type=Maildir

Also, add the following macros to .muttrc for use with notmuch:

macro index <F8> \
"<enter-command>set my_old_pipe_decode=\$pipe_decode my_old_wait_key=\$wait_key nopipe_decode nowait_key<enter>\
<shell-escape>notmuch-mutt -r --prompt search<enter>\
<change-folder-readonly>`echo ${XDG_CACHE_HOME:-$HOME/.cache}/notmuch/mutt/results`<enter>\
<enter-command>set pipe_decode=\$my_old_pipe_decode wait_key=\$my_old_wait_key<enter>i" \
"notmuch: search mail"

macro index <F9> \
"<enter-command>set my_old_pipe_decode=\$pipe_decode my_old_wait_key=\$wait_key nopipe_decode nowait_key<enter>\
<pipe-message>notmuch-mutt -r thread<enter>\
<change-folder-readonly>`echo ${XDG_CACHE_HOME:-$HOME/.cache}/notmuch/mutt/results`<enter>\
<enter-command>set pipe_decode=\$my_old_pipe_decode wait_key=\$my_old_wait_key<enter>" \
"notmuch: reconstruct thread"

macro index l "<enter-command>unset wait_key<enter><shell-escape>read -p 'notmuch query: ' x; echo \$x >~/.cache/mutt_terms<enter><limit>~i \"\`notmuch search --output=messages \$(cat ~/.cache/mutt_terms) | head -n 600 | perl -le '@a=<>;chomp@a;s/\^id:// for@a;$,=\"|\";print@a'\`\"<enter>" "show only messages matching a notmuch pattern"

These macros define search hotkeys for notmuch. F8 lets you enter a search query and F9 expands the message under your cursor into the entire thread from which it came. The regular hotkey ‘l’ (limit) is overridden here to provide functionality similar to F8. I’m not sure yet which is the better of the two options.

Step 1: offlineimap

We install offlineimap and sync all the email from the server to your client.

First, install offlineimap:

# apt-get install offlinemap

Then, create ~/.offlineimaprc:

[general]
accounts = Prive

[Account Prive]
localrepository = PriveLocal
remoterepository = PriveRemote
status_backend = sqlite
postsynchook = notmuch new

[Repository PriveRemote]
type = IMAP
remotehost = imap.example.org
remoteuser = <username>
remotepass = <password>
ssl = yes
sslcacertfile = /etc/ssl/certs/ca-certificates.crt

[Repository PriveLocal]
type = Maildir
localfolders = ~/Maildir
restoreatime = no

Note that you need different settings for a Gmail account, because the folder names for Gmail are different.

Set the read permissions on .offlineimaprc to user only, because it now contains your email password.

Next, download all your email. This may take a significant amount of time (for 9GB of email, it took me all night), but if you cancel the process with Ctrl+C, it picks up where it left off when you start it again:

$ offlineimap

Step 2: notmuch

First, install the notmuch and notmuch-mutt packages:

# apt-get install notmuch notmuch-mutt

This also pulls in some Perl dependencies for the notmuch-mutt script.

Next, configure notmuch:

$ notmuch setup

Set it up to point to the Maildir that offlineimap created for you.

Now, index all your email in your local Maildir:

$ notmuch new

Step 3: msmtp

First, install msmtp, a lightweight MTA:

# apt-get install msmtp

Configure msmtp by creating ~/.msmtprc

# Set default values for all following accounts.
defaults
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log

account prive
host smtp.example.org
port 587

from user@example.org
auth on
user <username>
password <password>

account default: prive

Set the read permissions of .msmtprc to user only, because it now contains your email submission password.

Copy the scripts msmtp-enqueue.sh and msmtp-runqueue.sh to ~/bin, or wherever .muttrc and the following script will look for them. In Ubuntu, they are stored by default in `/usr/share/doc/msmtp/examples/msmtpqueue/ . These scripts will be used to put mail that you send in a queue, which can be run whenever you are online later.

Step 4: Automatically check and submit email

Create a script checkmail.sh somewhere in your path:

#!/bin/sh

STATE=`nmcli networking connectivity`

if [ $STATE = 'full' ]
then
    ~/bin/msmtp-runqueue.sh
    offlineimap
    exit 0
fi
echo "No internet connection."
exit 0

Make this script executable. This is the script that you will run to manually check for new email and submit email that you put in the queue for submission earlier. We will also make a cronjob to run it automamtically every hour.

Using crontab -e, add the following line to your user crontab:

8 * * * * ~/bin/checkmail.sh 2>&1 | logger -tcheckmail

Every hour, at eight minutes past, it will check for new email and submit enqueued email.

Step 5: You’re done!

Enjoy your setup!