Mailsammlung
Einleitung
Wer kennt das nicht: Im Laufe der Jahre mit demselben Mail-Account sammeln sich Mails und oft liegen noch irgendwo wichtige Informationen oder Kontakte, die sich eben nur in diesem Berg befinden. Befindet sich der Account bei Googlemail, kann nman alles bequem durchsuchen. Aber ich habe meine Mails auf dem Laptop und will nicht alles hochladen.
Wir starten gleich mit dem Projekt. Informationen, die ich im Laufe des Projekts rechercieren musste, stelle ich als Einschub oder separaten Artikel zur Verfügung. Das Github-Repo mit dem kompletten Code ist unten verlinkt.
Ziel
Was schrieb mir der Hausmeister wegen dem Wasserschaden? Diese Frage lässt sich mit der normalen Volltextsuche oft nicht beantworten – zumindest nicht zuverlässig.
E-Mails enthalten nicht immer exakt die Wörter, nach denen wir suchen. Manchmal steht statt „Wasserschaden“ nur „Rohrbruch“ oder „Feuchtigkeit im Keller“. Statt „Hausmeister“ vielleicht „Herr Keller“ oder „Technischer Dienst“. Wer seine Mails dennoch semantisch durchsuchen will, braucht mehr als nur grep
– nämlich Embeddings.
In diesem Artikel bauen wir ein kleines semantisches Suchsystem, das:
- E-Mails aus Thunderbird lokal verarbeitet
- Embeddings aus den Mailtexten erzeugt
- einen Vektorindex zur schnellen Ähnlichkeitssuche verwendet
- relevante Mails zu einer Frage findet
- ein kleines Sprachmodell lokal über Ollama nutzt, um eine Antwort zu formulieren
Und das Ganze läuft lokal, offline, transparent – mit freier Software.
Projekt einrichten
Ich richte meine Python-Projekte inzwischen gerne mit uv ein. Dieses Rust-Tool ist extrem schnell, unkompliziert und setzt die komplette Projektstruktur einschließlich .venv
auf. Das Kompilieren der CUDA-Unterstützung funktionierte bei mir nur mit Python 3.9:
|
|
Mails aus Thunderbird extrahieren
Thunderbird speichert alle E-Mails im MBOX-Format. Diese Dateien befinden sich in der Regel unter:
- Linux/macOS:
~/.thunderbird/<profil>.default-release/Mail/Local Folders/Inbox
- Windows:
C:\Users\<Benutzer>\AppData\Roaming\Thunderbird\...
Wir extrahieren die Mails per Python:
|
|
Bei kaputten Mails kann die Extraktion des Payloads fehlschlagen – eine robustere Version des Skripts findet sich im Git-Projekt.
Hardware-Beschleunigung
Um zu prüfen, ob Deine Umgebung CUDA (NVIDIA-GPU) oder Apple MPS (Metal Performance Shaders) unterstützt, kannst Du folgendes ausführen:
|
|
Für CUDA musst Du einen passenden PyTorch-Build installiert haben, z. B. mit --index-url https://download.pytorch.org/whl/cu121
. Auf Apple Silicon wird MPS genutzt.
Mail-Inhalte vektorisieren
Für die semantische Suche nutzen wir ein kleines, effizientes Modell aus sentence-transformers:
|
|
Das Modell findet sich danach im Cache unter $HOME/.cache/huggingface/
und wird von den nachfolgenden Skripten verwendet.
Vektorindex mit FAISS bauen
Der nächste Schritt ist die Vektorisierung und die Erstellung des Indexes. Der folgende Codeausschnitt verdeutlicht das. Das komplette Skript ist im Git-Repo, dort wird der Index auch als Datei gespeichert.
|
|
Cosinus-Ähnlichkeit
Die Cosinus-Ähnlichkeit misst, wie ähnlich zwei Vektoren in ihrer Richtung sind – unabhängig von ihrer Länge. Sie ist die gängigste Metrik für Embeddings.
$$ \text{cosine\_similarity}(\vec{a}, \vec{b}) = \frac{\vec{a} \cdot \vec{b}}{\|\vec{a}\| \cdot \|\vec{b}\|} $$dabei ist $|\vec{a}|$ die euklidische Norm von $\vec{a}$
$$\|\vec{a}\| = \sqrt{\sum_{i=1}^n a_i^2}$$– also einfach der Pythagoras im $n$-dimensionalem. Das Ergebnis bei Embeddings ist in $[0, 1]$, da alle Vektoren positiv sind.
In Python gibt es fertige Bibliotheksfunktionen dafür:
|
|
Suche starten
Sobald der Index vorhanden ist, können wir diesen für eine einfache Suche verwenden:
|
|
Antwort formulieren mit Ollama
Ollama kurz erklärt
Ollama ist ein Tool zum lokalen Ausführen von Sprachmodellen (LLMs), z. B. phi, mistral, llama3. So richtest Du es ein:
|
|
Danach können wir das Modell aus Python mit dem REST-API von Ollama ansprechen. Wir übergeben die aufgrund des Kontexts gefundenen Mail mit dem Promt.
|
|
Retrieval-Augmented Generation (RAG)
Die Anfrage wird per Embedding mit den Mails im Vektorraum verglichen. Nur die relevantesten Mails werden als Kontext in den Prompt eingefügt. Ollama formuliert basierend darauf eine Antwort.
Das Sprachmodell hat also keinen Zugriff auf alle Mails, sondern bekommt gezielt Kontext mitgeliefert.
Fazit
Wir haben ein einfaches, aber mächtiges Tool gebaut, um E-Mails semantisch zu durchsuchen – ganz ohne Cloud, Gmail oder Microsoft 365. Die Kombination aus lokalem Embedding-Modell und Ollama ist leichtgewichtig, schnell und privat.