Notmuch - fulltextové vyhledávání mailů

Máte-li vlastní mailový server, ale občas vám chybí rychlost a možnosti vyhledávání v gmailu, čtěte dál.

Notmuch jako součást mailového klienta

Slyšeli jste už o fulltextovém vyhledávači emailů 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 totiž je, že vyžaduje mít lokální kopii všech emailů v maildir formátu. Vlastně to nemusí být přímo maildir formát, stačí aby každý email byl ve zvlášť textovém souboru. Maildir formát ale podporuje málokterý mailový 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 email 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 by jste navíc chtěli maily číst na více různých počítačích, musíte řešit synchronizaci tagů mezi počítači. Bohužel tyto vlastnosti odrazují naprostou většinu potencionálních uživatelů a dělají z něj něco okrajového.

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

Notmuch přímo na mailovém serveru

Pokud máte vlastní mailový server, pravděpodobně již maildir formát používáte (nebo by jste snadno mohli), protože tam je maildir formát naopak obvyklý. Problém s ukládáním emailů v maildir 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 nejednoduší řešení - provádět indexaci přímo na mail server pomocí Notmuch nenapadlo? Předpokládám, že to bude tím, že málo který 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ř. zobrazit všechny emaily či troubletickety konkrétního zákazníka, protože Notmuch dovede vrátit výsledky vyhledávání i v json formátu.

Konfigurace a indexace

Po nainstalování notmuch (v debiaun 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 a tam si ukládá svou databázi indexů ze všech mailů co najde v zadaném adresáři a jeho podadresářích.

V jednom indexu tak lze mít emaily různých uživatelů, dokonce i na více jak jedné doméně. Ve výsledku je tak možné zachytit např. veškerou komunikaci s konkrétním zákazníkem, bez ohledu na to, kdo konkrétně a z jakého emailu 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 dále každý update indexace provedeme příkazem

notmuch new

První indexace může trvat několik minut až celou noc podle množství emailů. V každém případě na konci indexování, i kdyby jste měli emailů přes milion, Notmuch v vtipně konstatuje, že moc emailů 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ý email asi hledat ještě nebudete. Pokud přibudou jen desítky emailů, opětovné provedení notmuch new trvá už jen vteřiny.

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í emailů více, chtělo by to nějaký přehlednější výpis s možností nahlížet i do těl emailů. 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. Formát mbox ukládá jednotlivé emaily 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 by zobrazení lépe vyhovovalo 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 u a vždy celého odesilatele a 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 bashovské 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í.

Pokud chci vyhledat všechny emaily a troubletickety jednoho zákazníka použiji např.

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ží trouble ticket na webových stránkách, automaticky systém vloží číslo zákaznického účtu a jeho mobilní telefon do předmětu. Je pak snadné zobrazit veškeré trouble tickety i kdyby najednou komunikoval z jiného emailu.

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 emailů mnoho, můžeme jejich počet omezit obdobím. Níže uvedený příklad hledá v emailech za posledních 60 dní výskyty slova “Hospodaření” (velikost písmen se nerozlišuje) .

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ějaké maily vyloučit pomocí znaku “-” nebe též operátor “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ím webové stránce

Pokud mají mít možnost vyhledávat v emailech všichni zaměstnanci a ne jen ti co mají přístup do konzole na mailovém serveru, může být nutné výsledky zobrazit na webových stránkách. Pro tento případ můžeme využít výsledky hledání vracené pomocí json. V ukázce níže hledám email pomocí id, je tedy logické, že výsledkem bude jediný email.

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

jq je command-line JSON processor, který pomůže json 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ý email 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”.

V json výsledku 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 o jaký mailový účet (kontakt@domena.cz) jestli byl email odpovězen (“R”), přečten (“S”), přeposlán(“P”), případně definové tagy- barvičky emailu (v ukázce “a” a “g”, tedy jméno souboru končí “ag”). Viz dokumentace toho jak je vytvořen název souboru v maildir formátu.

Emaily co spolu tvoří vlákno (tedy třeba odpověď) lze rozpoznat pomocí zanoření v json. Že máte zanoření emailů na webu zobrazeno správně poznáte porovnáním s tím co zobrazuje pro stejný dotaz mutt. Těla emailů jsou defaultně 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ý email co obsahuje HTML, by správně měl obsahovat i textovou variantu téhož emailu, tedy zobrazovat jen textovou variantu by mělo být dostatečné. Pokud bychom přecijen chtěli, aby Notmuch vracel v json i HTML verzi emailů (pokud je v emailu obsažena), přidáme parametr –include-html.

Maximální počet nalezených mailů nejde omezit, je proto dobré si proto předem zjistit, kolika emailů vyhovuje našemu dotazu.

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

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

Jak u nás pracujeme s maily ?

Jsme menší firma s větším množstvím emailů. 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í emailů do konverzací (po vzoru Gmailu) používám addon Conversation, ale moc dobře to nefunguje, zapomíná to zobrazovat především odeslané emaily 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ášť souboru s názvem podle id emailu. Poznámky - textové soubory - synchronizujeme mezi různými počítači pomocí Syncthing nebo dříve Dropbox. Není to moc elegantní, ale více méně to funguje. Jaký způsob práce s maily volíte vy?

 
notmuch_clanek.txt · Last modified: 2022/09/01 11:26 by root