Skip to content

hyperreal.coffee

Using offlineimap and podman to archive mail

Problem

  • I want to keep an archive of my email on my local machine for storage and record-keeping.

  • I use Proton Mail as an email provider, so I have to use the Proton Mail Bridge app. I have the Flatpak version installed and set to run when I login to my desktop.

  • I run Fedora Silverblue (actually it's my own custom variant called Vauxite, but that's not relevant here), so I have to run offlineimap from a Podman container on the host. Another way would be to use systemd inside the toolbox container, but there's no guarantee that the toolbox container will be running when I need to pull my local mail from the remote server.

  • Ideally, I'd have offlineimap run daily at, say, 10:00 PM. On a non-immutable OS, I'd just use the offlineimap systemd service and timer. Thankfully, Podman has the ability to generate a systemd unit file for containers.

Solution

The first thing I did was create a Dockerfile (or, in OCI parlance, a Containerfile).

FROM fedora:latest
LABEL maintainer "Jeffrey Serio <hyperreal@fedoraproject.org>"

RUN printf "fastestmirror=True\ndeltarpm=True\nmax_parallel_downloads=10\n" | tee -a /etc/dnf/dnf.conf \
    && dnf install -y offlineimap python3-distro \
    && dnf clean all \
    && mkdir /{mail,metadata}

CMD ["/usr/bin/offlineimap", "-o", "-u", "basic", "-c", ".offlineimaprc"]

I then built the container image locally:

podman build -t localhost/offlineimap:latest .

Once that was done, I created a container for it. I mapped the offlineimap metadata directory, mail directory, and offlineimaprc as volumes for the container:

podman create -it --name offlineimap \
    -v ~/mail:/mail:Z \
    -v ~/.offlineimap-metadata:/metadata:Z \
    -v ~/.offlineimaprc:/.offlineimaprc:Z \
    localhost/offlineimap:latest

Note that the use of :Z for volumes only applies to SELinux-enabled hosts. On SELinux hosts, when a container starts, it is given an SELinux context on the host. In order for processes inside the container to write to a volume mapped on the host, the volume needs an SELinux context that those processes can access. We get a permission denied error because the volume's MLS level and the in-container process's MLS level are different. For more information, see the link below.

With the container created, I can now run the podman command to generate the systemd unit file.

  • --new: Sets the container to be created and removed before and after each run with the --rm flag.

  • --name: Name of the container to generate the systemd unit file from.

  • --files: Outputs the files to the current working directory instead of stdout.

podman generate systemd --new --name offlineimap --files

The file looks like this:

# container-offlineimap.service
# autogenerated by Podman 4.1.1
# Tue Aug 16 12:45:40 CDT 2022

[Unit]
Description=Podman container-offlineimap.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run \
	--cidfile=%t/%n.ctr-id \
	--cgroups=no-conmon \
	--rm \
	--sdnotify=conmon \
	-d \
	--replace \
	-it \
	--name offlineimap \
	--network host \
	-v /var/home/jas/mail:/mail:Z \
	-v /var/home/jas/.offlineimap-metadata:/metadata:Z \
	-v /var/home/jas/.offlineimaprc:/.offlineimaprc:Z localhost/offlineimap
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target

Now I have to create a systemd timer for this service:

[Unit]
Description=Run container-offlineimap.service daily at 22:00:00

[Timer]
OnCalendar=*-*-* 22:00:00
Persistent=true

[Install]
WantedBy=timers.target

I move these files to ~/.config/systemd/user, and enable the timer in user mode:

systemctl --user enable --now container-offlineimap.timer

So now, at 10:00 PM every night, the systemd timer will trigger the container-offlineimap.service, which will pull mail from the remote Proton Mail server and store it in the /var/home/jas/mail directory. Yay!

END

Last updated: 2022-08-17