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:

EigenschaftWert
Namegrommunio: Search Index Completeness (worst mailbox)
Keygrommunio.index.worst_ratio
TypeZabbix Agent
Value TypeUnsigned Integer
Interval15m
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

  1. “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.

  2. 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.

  3. 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 -A nach der Migration sollte Standard sein.

Checkliste: grommunio-Suche debuggen

  • Sind die Mails in exchange.sqlite3 vorhanden? (message_properties nach Subject/Sender durchsuchen)
  • Ist grommunio-index installiert 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