Du siehst drei Discord-Mails im Posteingang. Du suchst nach “discord”. Null Treffer. Was?
Das Symptom
Die Suche in grommunio-web findet Mails nicht, die sichtbar im Posteingang liegen. Betroffen sind sowohl Suchen nach Absender-Namen als auch nach Betreffzeilen anderer Mails.
Das Tückische: Es gibt keine Fehlermeldung. Die Suche läuft durch, findet nur nichts.
TL;DR
grommunio-index -c -v -A — vollständiger Neuaufbau des Suchindex für alle Mailboxen. Der inkrementelle Index hatte stillschweigend aufgehört, neue Mails zu indizieren.
Die Diagnose
Wo steckt “discord”?
Erst prüfen, ob die Mails überhaupt in der Datenbank existieren:
sqlite3 /var/lib/gromox/user/<DOMAIN>/<USER>/exmdb/exchange.sqlite3 \
"SELECT mp.propval FROM message_properties mp
WHERE mp.proptag = 0x0042001f
AND CAST(mp.propval AS TEXT) LIKE '%discord%' LIMIT 5;"
Ergebnis: 10+ Treffer. Die Mails sind da — mit “Discord” als PR_SENT_REPRESENTING_NAME (Absender-Anzeigename). Im Subject steht dagegen sowas wie “r2d2 hat dich in Hoth erwähnt.” — kein Wort “discord”.
Durchsucht grommunio-web den Absender?
Ja. Die Standard-Suchfelder für Mail in grommunio-web:
// Zarafa.mail.data.SearchFields
value: 'subject sender_name sender_email_address
sent_representing_name sent_representing_email_address
body display_to display_cc'
sender_name und sent_representing_name sind dabei. Das Problem liegt nicht im Client.
Der Volltextindex
Grommunio nutzt grommunio-index — ein separates Paket das FTS5-SQLite-Indizes pro Mailbox erstellt:
# Index-Einträge zählen
sqlite3 /var/lib/grommunio-web/sqlite-index/<USER>@<DOMAIN>/index.sqlite3 \
"SELECT count(*) FROM messages;"
# → 10558
# Tatsächliche Mails in der Mailbox
sqlite3 /var/lib/gromox/user/<DOMAIN>/<USER>/exmdb/exchange.sqlite3 \
"SELECT count(*) FROM messages m
JOIN message_properties mp ON m.message_id = mp.message_id
WHERE mp.proptag = 0x001A001f AND mp.propval LIKE 'IPM.Note%';"
# → 22365
47% indiziert. Mehr als die Hälfte der Mails fehlt im Suchindex.
Und der entscheidende Test:
sqlite3 /var/lib/grommunio-web/sqlite-index/<USER>@<DOMAIN>/index.sqlite3 \
"SELECT count(*) FROM messages WHERE messages MATCH 'discord';"
# → 0
Null. Discord ist nicht im Index.
Die Ursache
grommunio-index läuft per systemd-Timer alle ~15 Minuten und aktualisiert den Index inkrementell. Es trackt den letzten Synchronisationspunkt pro Ordner in einer hierarchy-Tabelle (commit_max, max_cn).
Wenn dieser Tracking-Zustand aus dem Tritt gerät — etwa nach einer Migration von Kopano, nach Massenmoves zwischen Ordnern, oder nach einem Crash — überspringt der inkrementelle Modus stillschweigend Mails. Keine Fehlermeldung, kein Warning im Log. Der Index wächst einfach nicht mehr mit.
Die Lösung
Sofort-Fix: Index komplett neu aufbauen
# Einzelne Mailbox
grommunio-index -c -v /var/lib/gromox/user/<DOMAIN>/<USER> \
-e ::1 -o /var/lib/grommunio-web/sqlite-index/<USER>@<DOMAIN>/index.sqlite3
# ALLE Mailboxen auf einmal
grommunio-index -c -v -A
Wichtig: -c (create) löscht den alten Index und baut komplett neu auf. Ohne -c wird nur inkrementell aktualisiert — und genau das war ja das Problem.
Auf einem Server mit ~65.000 Mails über alle Mailboxen dauert der Neuaufbau ca. 3,5 Minuten.
Ergebnis
Vorher: 10558 indiziert → "discord" MATCH: 0
Nachher: 21204 indiziert → "discord" MATCH: 111
Damit es nicht wieder passiert: Zabbix-Monitoring
Ein UserParameter-Script das den schlechtesten Index-Ratio aller Mailboxen prüft:
/usr/local/bin/grommunio-index-check.sh:
#!/bin/bash
# Schlechtester Index-Ratio aller aktiven Mailboxen (Prozent)
# Vergleicht nur E-Mails (IPM.Note%) — Kalender/Kontakte ignoriert
# Mailboxen mit <100 Mails ignoriert
worst=100
for indexdb in /var/lib/grommunio-web/sqlite-index/*/index.sqlite3; do
user_dir=$(basename "$(dirname "$indexdb")")
user=$(echo "$user_dir" | sed "s/@.*//")
domain=$(echo "$user_dir" | sed "s/.*@//")
exmdb_path=""
for p in /var/lib/gromox/user/${domain}/${user}*/exmdb/exchange.sqlite3; do
[ -f "$p" ] && exmdb_path="$p" && break
done
[ -z "$exmdb_path" ] || [ ! -f "$exmdb_path" ] && continue
total=$(sqlite3 "$exmdb_path" \
"SELECT count(*) FROM messages m
JOIN message_properties mp ON m.message_id = mp.message_id
WHERE mp.proptag = 0x001A001f
AND mp.propval LIKE 'IPM.Note%';" 2>/dev/null)
[ -z "$total" ] || [ "$total" -lt 100 ] && continue
indexed=$(sqlite3 "$indexdb" \
"SELECT count(*) FROM messages;" 2>/dev/null)
[ -z "$indexed" ] && indexed=0
ratio=$((indexed * 100 / total))
[ "$ratio" -gt 100 ] && ratio=100
[ "$ratio" -lt "$worst" ] && worst=$ratio
done
echo "$worst"
Zabbix-UserParameter (/etc/zabbix/zabbix_agent2.d/grommunio_index.conf):
UserParameter=grommunio.index.worst_ratio,/usr/local/bin/grommunio-index-check.sh
Zabbix-Item:
| Eigenschaft | Wert |
|---|---|
| Name | grommunio: Search Index Completeness (worst mailbox) |
| Key | grommunio.index.worst_ratio |
| Type | Zabbix Agent |
| Value Type | Unsigned Integer |
| Interval | 15m |
| Unit | % |
Trigger: max(/mail-chewbacca/grommunio.index.worst_ratio,#3)<80 — feuert wenn der Index dreimal hintereinander unter 80% liegt.
Pitfall: Was zählt als 100%?
Die Tabelle messages in exchange.sqlite3 enthält alle MAPI-Items — E-Mails, Kalendereinträge, Kontakte, Aufgaben, Notizen. Der Suchindex enthält nur E-Mails.
Wenn du den Ratio naiv berechnest (indexed / total_messages), bekommst du bei Mailboxen mit vielen Kalendereinträgen immer einen niedrigen Wert. Deshalb filtert das Script nach IPM.Note% (Property Tag 0x001A001f = PR_MESSAGE_CLASS).
Lessons Learned
“Suche geht nicht” ist nicht gleich “Suche ist kaputt” — Der Client und der Server funktionieren korrekt. Der Index dazwischen war unvollständig. Kein Fehler in den Logs.
Inkrementelle Indizes brauchen Monitoring — Jedes System das inkrementell synchronisiert kann aus dem Tritt geraten. Ohne Monitoring merkst du es erst wenn ein User sich beschwert.
Nach Migrationen: Immer Index neu aufbauen — Wenn du von Kopano, Zarafa oder einem anderen System migrierst, rechne damit dass der inkrementelle Index die migrierten Mails nicht sauber aufnimmt. Ein
grommunio-index -c -Anach der Migration sollte Standard sein.
Checkliste: grommunio-Suche debuggen
- Sind die Mails in
exchange.sqlite3vorhanden? (message_propertiesnach Subject/Sender durchsuchen) - Ist
grommunio-indexinstalliert und aktiv? (systemctl status grommunio-index.timer) - Wie viele Mails sind indiziert vs. tatsächlich vorhanden? (Ratio prüfen)
- Findet der Index den Suchbegriff? (
messages MATCH 'suchbegriff'in index.sqlite3) - Index neu aufbauen:
grommunio-index -c -v -A - Monitoring einrichten damit es nicht wieder passiert