Ich habe die Erfahrung gemacht, dass offlineimap sehr viel Arbeitsspeicher verbraucht, wenn man es permanent laufen lässt. Das Problem lässt sich umgehen, lässt man es stattdessen durch einen systemd-Timer (oder Cronjob) aufrufen.

Der systemd-Timer hat ein kleines nettes Detail als Vorzug gegenüber einem Cronjob: Man kann ihn immer erst dann starten, wenn die Unit, also in dem Fall offlineimap schon eine definierte Zeit lang inaktiv ist. Im Fall von offlineimap heißt das also, dass man auch bei längeren Synchronisationsvorgängen über eine langsame Verbindung nicht in Gefahr läuft, dass ein zweiter Prozess gestartet werden soll, wenn der erste noch dabei ist, Mails herunterzuladen und die Datenbank zu verändern. Das gewählte Intervall beginnt erst, wenn die Ausführung der Unit abgeschlossen ist.

Haken: Kennworte aus einem Kennwortspeicher

Kennworte, vor allem die für Mail-Konten, im Klartext irgendwo zu speichern ist nie eine gute Idee. Besser ist da schon die Verwendung von z.B. KeePass oder des Schlüsselsrings der Desktopumgebung. Hat man, etwa direkt beim Login in die Desktopumgebung, den Schlüsselring entsperrt, kann man über secret-tool ein Kennwort aus dem Schlüsselring anfordern. Das funktioniert aber nicht, wenn ein Prozess nicht in Abhängigkeit der grafischen Oberfläche und der dort laufenden Sitzung gestartet wurde. Es fehlt die dazugehörige Umgebungsvariable, welche den Pfad zum DBUS-Sitzungsbus angibt, über den die Kommunikation mit dem Schlüsselring läuft. Periodische Ausführung von Programmen wie offlineimap scheitern also, wenn sie über systemd gestartet werden, weil dann kein Bezug zur grafischen Oberfläche besteht.

Workaround

ein klein wenig unsicherer

Zuerst zur Sicherheit: Ich verwende also einen Workaround, der ein klein wenig unsicherer ist, da ich die Verwendung meiner DBUS-Sitzung von der grafischen Oberfläche entkopple. Gleichzeitig vermeide ich aber so auch, dass ich das Kennwort im Klartext irgendwo hinterlegen muss. Während mein Rechner also läuft, kann mein DBUS von allen Prozessen verwendet werden, die als mein Nutzer laufen. Ohne den noch zu beschreibenden Workaround wäre das (erstmal) nur möglich, wenn ein Einbruch etwa durch eine Sicherheitslücke aus dem Desktop-Kontext käme, also in einem unter der grafischen Oberfläche gestarteten Anwendungsprogramm (ob mutt auf der Konsole oder Firefox spielt dabei ja keine Rolle). Dieser „Schutz” ist aber sowieso schon sehr dünn, da er quasi nur aus der Geheimhaltung der Adresse zum DBUS-Socket besteht. Die lässt sich unter meinem Benutzerkontext aber auch trivial herausfinden.

Ergebnis der Überlegungen also: minimal geschwächte Sicherheit zur Laufzeit, viel bewahrte Sicherheit in Ruhe (Laptop aus), weil das Kennwort nicht unverschlüsselt irgendwo notiert ist.

DBUS aus systemd heraus ansprechen

Die Lösung ist, wenn man sich erstmal die Funktion von DBUS in dem Fall angesehen hat, ziemlich einfach:

Man startet aus der Desktop-Umgebung heraus nach dem Login ein Script, was die nötigen Werte der Umgebungsvariablen in eine Datei schreibt, die man dann später aus systemd referenzieren kann. Dann klappt auch der Abruf von Kennworten aus dem Keyring:

Ich habe also ein Script ~/.local/bin/export-dbus.sh:

#!/bin/bash
touch $HOME/.dbus_addr
chmod 600 $HOME/.dbus_addr
env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.dbus-addr
echo "export DISPLAY=:1" >> $HOME/.dbus-addr
echo "export DBUS_SESSION_BUS_ADDRESS" >> $HOME/.dbus-addr

Dieses Script wird zum Autostart der Desktopumgebung hinzugefügt, dazu braucht man eine Datei ~/.config/autostart/export-dbus.desktop:

[Desktop Entry]
Name=DBUS Address export
Comment=Make DBUS session bus available outside the DE
Exec=~/.local/bin/export-dbus.sh
Terminal=false
Type=Application
Categories=System
StartupNotify=false

systemd-Timer einrichten

Viel besser oder schlechter sind die Timer von systemd gegenüber Cronjobs auch nicht. Nur anders. Um alle 10 Minuten E-Mails via IMAP synchronisieren zu lassen, richtet man folgende zwei Units ein:

Den eigentlichen Dienst, ~/.config/systemd/user/offlineimap.service:

[Unit]
Description=OfflineIMAP
After=network.target

[Service]
Type=simple
ExecStart=~/.local/bin/offlineimap

und den dazugehörigen Timer:

[Timer]
OnUnitInactiveSec=600
Unit=offlineimap.service

Wie man im Dienst schon gesehen hat, habe ich noch einen Wrapper für offlineimap erstellt. In diesem wird die vorhin gespeicherte DBUS-Adresse noch verfügbar gemacht:

#!/bin/bash

# Wrapper to make offlineimap with GNOME Keyring usable from systemd
source $HOME/.dbus-addr

# Run the original offlineimap
/usr/bin/offlineimap

Ausführen

Man muss nur noch den Timer aktivieren:

systemctl enable --user offlineimap.timer
systemctl start --user offlineimap.timer

und den Dienst anstoßen:

systemctl enable --user offlineimap.service
systemctl start --user offlineimap.service

Ob alles klappt, kann man im Log beobachten:

journalctl -f