This is a Python program to back up messages from your Fastmail JMAP mailbox.
Based on the amazing work by Nathan Grigg 🙏
requests
moduleTo get the module, either install it in a virtualenv, or globally with:
PIP_REQUIRE_VIRTUALENV=false python3 -m pip install --break-system-packages requests
Download the latest release or clone this repo (if you don't know how to do that, click the green Code button above, then Download ZIP)
Copy the jmap-backup.py
file to a directory in your $PATH
(I suggest /usr/local/bin
if you're unsure) and make sure it's executable (chmod +x jmap-backup.py
)
Create a configuration file (JSON) to store your API key, destination directory where the backup will be kept, and other settings. You can create multiple config files to back up different accounts or to keep copies on different storage (local, SMB/NFS etc).
A bare minimum config file must contain at least the dest_dir
and token
keys, for example:
{
"dest_dir": "/Volumes/storage/backups/Fastmail",
"token": "{your_api_key_here e.g. fmu1-xxxxxx...}"
}
_The configuration is now in JSON format (prior to v1.1 it was stored as YAML). This change was made because Python can read and write it without requiring the PyYAML module. If you're not comfortable converting your legacy config file to JSON by hand, I suggest using
yq
:_yq -p yaml -o json fastmail.yml >fastmail.json
jmap-backup.py -c ~/.jmapbackup/fastmail.json
If you don't specify a config file with the
-c
option, the program will assume a default path of~/.jmapbackup/fastmail.json
Progress messages will be printed to the console. When the job is finished, you should see your messages in the destination directory, organized in folders in YYYY-MM
format. The individual messages are saved as standard .eml
format files with the filename made up of a datestamp, messageid and subject.
This is designed to run quickly and often, so running it daily is no problem and should complete within a minute or two. It's a good idea to stick it in your crontab or set up a LaunchAgent to trigger it at regular intervals. I suggest LaunchControl (no affiliation) if you're on a Mac and don't want to fiddle about with XML files.
Some have requested a Docker configuration to make it easier to set up and run, so I'm providing the basic instructions below. I have limited experience creating Docker images, so please make any suggestions or corrections via the issue tracker.
git clone https://github.com/luckman212/jmap-backup && cd jmap-backup
mkdir -p cfg backups/Fastmail
dest_dir
can either be a local Docker mount/volume or a network share if one is available to your container. Sample config file below:cat <<EOF >cfg/fm-docker.json
{
"delay_hours": 24,
"dest_dir": "/backups/Fastmail",
"not_before": "2020-01-01",
"token": "fmu1-xxxx..."
}
EOF
docker build -t jmap-backup .
docker logs -f jmap-backup-1
in another shell.docker run --rm \
--name jmap-backup-1 \
-v /root/jmap-backup/cfg:/cfg \
-v /root/jmap-backup/backups:/backups \
-e JMAP_DEBUG=true \
jmap-backup \
-c /cfg/fm-docker.json
Key | Description | Example value |
---|---|---|
delay_hours |
Back up only messages at least this many hours old | 24 |
not_before |
Cut off date before which messages will not be backed up | 2018-06-01 |
pre_cmd |
Command (and args) to run prior to execution, most often used to mount some remote storage location such as an SMB or NFS share. It is formatted as an array so you can provide additional args as needed. | (see below) |
post_cmd |
Command to run post-execution (e.g. unmount the share) | (see below) |
Example of pre/post commands in config file (~
chars will be expanded by Python):
{
"pre_cmd": [
"/sbin/mount", "-t", "smbfs",
"//luckman212:hunter2@nas/backups", "/mnt/jmap"
],
"post_cmd": [
"/sbin/umount", "-t", "smbfs", "/mnt/jmap"
]
}
JMAP_DEBUG
to True
to see additional debugging info printed to the console.NOT_BEFORE
to override the default of 2000-01-01
or whatever date is specified in the config fileEvery so often, it's a good idea to run the script with the additional --verify
argument. This will be slower, but will thoroughly check that every message in your mailbox exists on the filesystem, and will "fill in the blanks" if any are missing.
I've been using this script for a few months with good success, but it has been tested on exactly one system! So you may encounter issues. If you do, please report them.