Notmuch: fulltextové vyhledávání mailů přímo na poštovním serveru

28. 9. 2022
Doba čtení: 8 minut

Sdílet

 Autor: Depositphotos
Máte vlastní mailový server, ale občas vám chybí rychlost a možnosti vyhledávání, jakou znáte z GMailu? Popíšeme si nástroj Notmuch, vysvětlíme si, jak funguje a jak ho nasadit na vlastní hromadu pošty.

Slyšeli jste už o fulltextovém vyhledávači e-mailů notmuch? Možnosti vyhledávání jsou dobré, syntaxe vyhledávaní jednoduchá a přehledná. Jak to, že jste o něm ještě možná neslyšeli? Jeho hlavní nevýhoda je, že vyžaduje mít lokální kopii všech e-mailů ve formátu maildir. Vlastně to nemusí být přímo maildir, stačí, aby každý e-mail byl v samostatném textovém souboru. Maildir ale podporuje málokterý poštovní klient, a u těch, co to podporují, je podpora často experimentální.

Notmuch také nabádá uživatele k využívání svých tagů. Tedy jeden e-mail může mít neomezený počet tagů, ne jen jedno jediné jméno složky, kde je umístěn. Což použitelné mailové klienty ještě dále omezuje. Pokud byste navíc chtěli maily číst na více různých počítačích, musíte řešit synchronizaci tagů mezi nimi. Bohužel tyto vlastnosti odrazují naprostou většinu potenciálních uživatelů a dělají z tohoto užitečného nástroje něco okrajového.

Vypadá to, že typický uživatel Notmuch je linuxový vývojář, který odebírá vývojářské mailingové listy, ve kterých se potřebuje vyznat a nevadí mu přitom používání netradičních (často konzolových) mailových klientů.

Notmuch přímo na poštovním serveru

Pokud máte vlastní mailový server, pravděpodobně již formát maildir používáte (nebo byste snadno mohli), protože tam je maildir docela obvyklý. Problém s ukládáním e-mailů v tomto formátu tedy odpadá úplně bez práce a zaindexování nic nebrání. Indexy jsou uloženy v adresáři .notmuch, který funkci mail serveru nijak neovlivní. Jak je možné, že o použití Notmuch přímo na mail serveru není v dokumentaci ani mailing listech žádná zmínka? Předpokládám, že to bude tím, že málokterý linuxový vývojář (typický uživatel Notmuch) je zároveň správcem mailového serveru.

Na vyhledání Notmuch je možné napojit i firemní informační systém, například zobrazit všechny e-maily či troubletickety konkrétního zákazníka, protože Notmuch dovede vrátit výsledky vyhledávání i ve formátu JSON.

Konfigurace a indexace

Po nainstalování notmuch (v Debianu nebo Ubuntu pomocí apt install notmuch) jej stačí spustit příkazem:

$ notmuch

Ze všech položených otázek je podstatný jen dotaz na kořenový adresář mailů pro indexaci. Notmuch si vytvoří podadresář .notmuch, kam si ukládá svou databázi indexů ze všech mailů, které najde v zadaném adresáři a jeho podadresářích.

V jednom indexu tak lze mít e-maily různých uživatelů, dokonce i na více než jedné doméně. Ve výsledku je tak možné zachytit například veškerou komunikaci s konkrétním zákazníkem, bez ohledu na to, kdo konkrétně a z jakého e-mailu komunikaci prováděl. V nalezených mailových vláknech pak nechybí důležité maily jen proto, že byly přesunuty do jiné složky (někdy třeba i omylem), nebo jsou uloženy ve složce „Send“ místo složky „Inbox“.

První indexaci a každou další aktualizaci provedeme příkazem:

$ notmuch new

První indexace může trvat několik minut nebo třeba celou noc, to podle množství e-mailů. V každém případě na konci indexování, i kdybyste měli e-mailů přes milion, Notmuch vtipně konstatuje, že moc zpráv nemáte: „That's not much mail.“

Provádění indexace můžete zadat do cronu třeba každou hodinu, protože pět minut starý e-mail asi hledat ještě nebudete. Pokud přibudou jen desítky e-mailů, trvá aktualizace indexu jen pár sekund.

Vyhledávání

Pokud máte vytvořený index, můžete zkoušet v mailech vyhledávat. Výsledek se zobrazí vždy naprosto okamžitě.

$ notmuch search from:neco@seznam.cz

Vypíše něco jako:

thread:000000000004cda1   2010-08-10 [4/9(14)] Jméno odkud| Jménu komu; Předmět (inbox replied)

Pokud ale dotaz vrátí e-mailů více, chtělo by to nějaký přehlednější výpis s možností nahlížet i do těl zpráv. I to je ale snadné.

Výsledek vyhledávání tak můžeme snadno zobrazit třeba pomocí textového mailového klienta mutt přímo v konzoli.

$ notmuch show --format=mbox from:neco@seznam.cz > /tmp/result.mbox &&\
mutt -R -f /tmp/result.mbox && rm /tmp/result.mbox

Parametr --format=mbox  říká, že výsledky se mají uložit do formátu mbox. Ten ukládá jednotlivé e-maily do souboru za sebou, což je pro jednorázové použití efektivnější než vytváření spousty malých souborů nebo symlinků na ně.

Není to úplně nutné, ale aby zobrazení lépe vypadalo, do /etc/Muttrc nebo do ~/.muttrc jsem přidal následující řádky:

set pager_index_lines = 25
set pager_context = 3

set date_format="%y-%m-%d %R"

# zobrazuje vždy jméno i email jak odesilatele tak příjemce
# set index_format="%d %-40f %-20r %-60s"
# zobrazuje jen jméno odesilatele u každého emailu
set index_format="%d %-15n %-60s"

Chci totiž zobrazit celé datum včetně hodiny a vždy celého odesilatele i příjemce.

Pro lepší pohodlí vyhledávání se zobrazením v Muttu jsem si vytvořil bashovskou funkci, jejíž definici pak vložím do souboru .bashrc, abych ji měl k dispozici, kdykoli budu potřebovat.

notmuchm() {
   echo
   date -r  $(notmuch config get database.path)/.notmuch/xapian/iam*\
        "+'notmuch new' byl naposledy proveden %d-%m-%Y %H:%M:%S"
   echo
   pocet_emailu=$(notmuch count "$@");

    if (($? != 0)); then
         echo -n "Máte chybu v zadaných parametrech."
         echo " viz. 'man notmuch-search-terms' "
         echo
         return
    fi

    if (($pocet_emailu > 1000)); then
          echo -n "notmuch našel $pocet_emailu emailů,"
          echo " což je příliš."
          echo "Upřesněte dotaz."
          echo
          return
       elif (($pocet_emailu == 0 )); then
          echo "Notmuch nenašel žádný email."
          echo "Změňte dotaz, nebo aktualizujte index pomocí 'notmuch new'."
          echo
          return
    fi

   temp_file=$(mktemp /tmp/notmuchm.XXXXXXXXX.mbox)
   notmuch show --format=mbox  $@>$temp_file && mutt -R -f $temp_file
   rm $temp_file
}

Možné použití této funkce je třeba následující:

$ notmuchm '(from:petr.krcmar or to:petr.krcmar) and Raspberry'

V konzoli si pak velmi snadno a pohodlně mohu procházet výsledek hledání.

Autor: Petr Soukup

Pokud chci vyhledat všechny e-maily a troubletickety jednoho zákazníka, můžu použít:

$ notmuchm subject:7095696 or subject:608424631 or\
 from:zakaznik344@seznam.cz or to:zakaznik344@seznam.cz

Využiji totiž toho, že když zákazník založí ticket na webových stránkách, systém automaticky vloží číslo zákaznického účtu a jeho mobilní telefon do předmětu. Je pak snadné zobrazit veškeré tickety, i kdyby najednou komunikoval z jiného e-mailu.

Pokud potřebuji využít závorky nebo jiné znaky, které by mohl interpretovat bash, použiji escape znak \ nebo dám celý vyhledávací výraz do apostrofů.

$ notmuchm \(subject:7095696 or subject:608424631\) and\
  from:zakaznik344@seznam.cz or to:zakaznik344@seznam.cz
$ notmuchm '(subject:7095696 or subject:608424631) and\
  from:zakaznik344@seznam.cz or to:zakaznik344@seznam.cz'

Pokud je nalezených e-mailů mnoho, můžeme jejich počet omezit obdobím. Níže uvedený příklad hledá v e-mailech za posledních 60 dní výskyty slova „Hospodaření“ – na velikosti písmen nezáleží.

$ notmuchm Hospodaření and date:60days..now

Místo day(s) lze použít i hour(s), month(s) nebo year(s)

Pokud je výsledek stále příliš velký, mohu některé maily vyloučit pomocí znaku - nebo též operátorem not. Níže uvedené tři řádky jsou ekvivalentní (and není povinné) a vrátí stejné výsledky.

$ notmuchm Hospodaření and date:10months..now and not from:automat@fio.cz
$ notmuchm Hospodaření date:10months..now not from:automat@fio.cz
$ notmuchm Hospodaření date:10months..now -from:automat@fio.cz

Zobrazení výsledku hledání na vlastní webové stránce

Pokud mají mít možnost vyhledávat v e-mailech všichni zaměstnanci, a ne jen ti s přístupem do konzole serveru, je nutné výsledky zobrazit na webových stránkách. Pro tento případ můžeme využít výsledky hledání vracené pomocí formátu JSON. V ukázce níže hledám e-mail pomocí id, je tedy logické, že výsledkem bude jediný e-mail.

$ notmuch show --format=json --entire-thread=false\
  id:d83563b0a48f637ddf1b8513b54d@domena.cz|jq

Utilita jq je řádkový JSON processor, který pomůže výstup zobrazit čitelně. Balíček s ním se jmenuje taktéž jq.

[
  [
    [
      {
        "id": "d83563b0a48f637ddf1b8513b54d@domena.cz",
        "match": true,
        "excluded": false,
        "filename": [
          "/var/vmail/domena.cz/kontakt/cur/1659179908.M181950P1571016.mail,S=102175,W=103870:2,Sag"
        ],
        "timestamp": 1659179907,
        "date_relative": "56 mins. ago",
        "tags": [
          "inbox"
        ],
        "body": [
          {
            "id": 1,
            "content-type": "multipart/mixed",
            "content": [
              {
                "id": 2,
                "content-type": "text/plain",
                "content": "Prehrana zprava cislo 06-Infolinka záznamník,voicemail v priloze.\n"
              },
              {
                "id": 3,
                "content-type": "audio/ogg",
                "content-disposition": "inline",
                "filename": "710660_2022.07.30_13-18-00-399.ogg",
                "content-transfer-encoding": "base64",
                "content-length": 100053
              }
            ]
          }
        ],
        "crypto": {},
        "headers": {
          "Subject": "Hlasova zprava 715117198 -> 800515515 delka 25s",
          "From": "<voicemail@domena.cz>",
          "To": "kontakt@domena.cz",
          "Date": "Sat, 30 Jul 2022 13:18:27 +0200"
        }
      },
      []
    ]
  ]
]

V tomto případě se jedná o krátký e-mail s předmětem „Hlasova zprava 715117198 → 800515515 delka 25s“ a tělem „Prehrana zprava cislo 06-Infolinka záznamník,voicemail v priloze.“ a přílohou „710660_2022.07.30_13–18–00–399.ogg“.

Ve formátu JSON dostaneme vše, co bychom mohli pro zobrazení na webové stránce potřebovat. Z cesty názvu mailového souboru („filename“) je možné vyčíst nejen složku (v našem případě kořenová – INBOX) , ale i o jaký mailový účet šlo (kontakt@domena.cz), jestli bylo na e-mail odpovězeno („R“), zda byl přečten („S“), přeposlán („P“), případně definované tagy/barvičky e-mailu (v ukázce „a“ a „g“, tedy jméno souboru končí „ag“). Viz dokumentace toho, jak je vytvořen název souboru ve formátu maildir.

E-maily, které spolu tvoří vlákno (tedy třeba odpověď) lze rozpoznat pomocí zanoření ve struktuře JSON. Že máte zanoření e-mailů na webu zobrazeno správně, poznáte porovnáním s tím, co zobrazuje pro stejný dotaz mutt. Těla e-mailů jsou ve výchozím stavu v JSON jen ve své textové variantě, kterou by mělo být bezpečné zobrazit na webu. I tak ale můžete pro jistotu případné HTML tagy zneškodnit. Každý e-mail, který obsahuje HTML, by správně měl obsahovat i textovou variantu téhož obsahu, tedy zobrazovat jen textovou variantu by mělo být dostatečné. Pokud bychom přeci jen chtěli, aby Notmuch vracel v JSON i HTML verzi (pokud je obsažena), přidáme parametr --include-html.

Maximální počet nalezených zpráv není možné omezit, je proto dobré si proto předem zjistit, kolik e-mailů vyhovuje našemu dotazu.

$ notmuch count --output=messages from:neco@seznam.cz

V případě, že je nalezených e-mailů příliš, můžeme požádat uživatele o upřesnění dotazu a výsledek nezobrazit. Notmuch neumí stránkovat a vypisování tisíců nalezených e-mailů stejně nedává smysl.

ict ve školství 24

Jak u nás pracujeme s maily?

Jsme menší firma s větším množstvím e-mailů. Protože vyžadujeme podporu HTML jak pro příjem tak pro odesílání (kvůli vkládání obrázků a tabulek), používáme jako mailového klienta Thunderbird. Pro řazení e-mailů do konverzací (po vzoru GMailu) používám rozšíření Conversation, ale moc dobře to nefunguje, zapomíná zobrazovat především odeslané e-maily ze složky Send.

Pro psaní poznámek k jednotlivým mailům používám plugin Xnote++. Každá poznámka je uložena ve zvláštním souboru s názvem podle id e-mailu. Poznámky – textové soubory – synchronizujeme mezi různými počítači pomocí Syncthing nebo dříve Dropboxem. Není to moc elegantní, ale více méně to funguje. Jaký způsob práce s maily volíte vy?

Autor článku

Petr Soukup vystudoval VUT FIT v Brně, je jednatelem ve společnosti miniTEL s.r.o. provozující služby Odorik.cz (VoIP). Používá linuxovou distribuci Debian a programovací jazyk Ruby.