Disassembler

Artificial intelligence is no match for natural stupidity.
26února2017

Import PST a NSF souborů rovnou do Dovecotu


No dobře, import rovnou na Dovecot server to tak úplně není, nicméně postup, který v článku popíšu, zajistí částečnou automatizaci skrze konverzi do mbox formátu a ušetří hromadu času. V případě, že migrujete klientskou schránku z jiného hostingu nebo třeba jen z POP3 na IMAP, nejpřímočařejší postup je asi nasměrovat téhož mailového klienta do starého i nové umístění zároveň a myškou maily postupně přetahat. Za předpokladu, že je použita nějaká příčetná aplikace mailového klienta, není na tomto postupu v zásadě nic špatného. Pokud ale potřebujete přetahovat firmu o padesáti nebo více zaměstnancích, brzo vás to přestane bavit.

PST-to-mbox


Formát PST (Personal Storage Table), který se v Microsoftích aplikacích používá už nějakých 20 let, byl poměrně důkladně rozebrán a popsán. Jelikož mailový server s Dovecotem bude velmi pravděpodobně provozován na linuxovém serveru, s PST souborem v témž prostředí si hravě poradí knihovna libpst. Utilita readpst, která zmíněnou knihovnu používá, totiž umí přechroustat PST soubor a vyrobit z něj formáty Maildir a mbox. Maildir staví na principu jeden mail = jeden soubor, což znamená, že schránka s deseti tisíci maily bude mít v Maildir formátu deset tisíc souborů. Maildir tedy pro dávkové zpracování spíše nedoporučuju. Obzvlášť ne, pokud máte k dispozici artilerii v podobě Dovecotí administrační utility doveadm, která snad kromě hlasitého předčítání zvládá s maily dělat fakt všechno. Podotýkám, že osobně na svých mailserverech pro mailboxy používám Dovecotí vlastní formát mdbox. Dovecot mimo něj umí ještě další vlastní formát sdbox a pak výše zmíněný Maildir a mbox. Zkonvertuji tedy PST do mboxu a poté jej naimportuji do předem vytvořené schránky v mdbox formátu.

Na deb-based systémech je utilita readpst v balíku pst-utils. Šup tam s ním.

apt-get install pst-utils

Pak si do nějakého dočasného umístění nakopíruju PST soubor a pustím konverzi.

root@mail:/tmp# readpst -r box@example.com.pst
Opening PST file and indexes...
Processing Folder "Odstraněná pošta"
Processing Folder "Doručená pošta"
Processing Folder "Pošta k odeslání"
Processing Folder "Odeslaná pošta"
Processing Folder "Kalendář"
Processing Folder "Kontakty"
Processing Folder "Deník"
Processing Folder "Poznámky"
Processing Folder "Úkoly"
Processing Folder "Koncepty"
Processing Folder "Informační kanály RSS"
Processing Folder "Nastavení akce konverzace"
Processing Folder "Nastavení rychlého kroku"
Processing Folder "Nevyžádaná pošta"
        "box@example.com" - 14 items done, 0 items skipped.
        "Kalendář" - 0 items done, 3 items skipped.
        "Kontakty" - 0 items done, 2 items skipped.
        "Doručená pošta" - 100 items done, 7 items skipped.
        "Odeslaná pošta" - 100 items done, 0 items skipped.

Parametr -r říká, že se má vytvořit adresářová struktura podobná té v PST souboru a v příslušných podadresářích se objeví soubor zvaný mbox s vlastními daty. Například takto

root@mail:/tmp# tree box@example.com
box@example.com
├── Doručená pošta
│   └── mbox
├── Kalendář
├── Kontakty
└── Odeslaná pošta
    └── mbox

4 directories, 2 files

To je skoro fajn, nicméně takovouto strukturu doveadm nesežere. Jednak názvy adresářů obsahují UTF-8 znaky (mezery nevadí) a jednak doveadm očekává, že všechny mbox soubory budou rovnocenné a budou uloženy v jediném adresáři. Musíme tedy strukturu trochu upravit, což provedu přesunutím a přejmenováním. Přejmenovat můžu buď za pomoci utility iconv, o které jsem kdysi psal ve článku o převodu textu z UTF-8 do ASCII a která mi z diakritických paznaků udělá ASCII, anebo můžu použít opět doveadm a převést názvy na mUTF-7, kteréžto je u IMAPových mailboxů standardem. Navíc doveadm všechny operace provádí s jako uživatel, pod kterým dovecot obvykle běží, takže je potřeba upravit i oprávnění.

for MBOX in box@example.com/*/mbox; do mv "${MBOX}" "$(doveadm mailbox mutf7 "$(dirname "${MBOX}").mbox")"; done
chown -R vmail:vmail box@example.com

Skončíme tedy s následující strukturou (vynechávám prázdné adresáře), kterou už doveadm pochopí.

root@mail:/tmp# tree box@example.com
box@example.com
├── Doru&AQ0-en&AOE- po&AWE-ta.mbox
└── Odeslan&AOE- po&AWE-ta.mbox

Nyní tedy můžu slavnostně odpálit doveadm import, který data z mboxů načte a uloží do příslušných podadresářů v produkční schránce v mdbox formátu. Připomínám, že veškerá práce s doveadm předpokládá, že dovecot ví jak procházet svoji databázi uživatelů. V mém případě s virtuálními doménami to má na starosti korektní nastavení iterate_query v konfiguraci databáze.

doveadm import -u box@example.com mbox:/tmp/box@example.com import all

Předposlední parametr import značí název mailboxu (složky) pod účtem box@example.com ve které budou vytvořeny podadresáře se stejnými názvy, jako mají importované mbox soubory. Pokud bych chtěl obsah importovaných mboxů hned sloučit s příslušnými existujícími boxy, můžu opět využít doveadm, maily přesunout a prázdné boxy zbylé po importu smazat. Zde už zase použiji původní názvy v UTF-8.

doveadm move -u box@example.com "INBOX" mailbox "import/Doručená pošta.mbox" all
doveadm move -u box@example.com "Odeslaná pošta" mailbox "import/Odeslaná pošta.mbox" all

doveadm mailbox delete -u box@example.com "import/Doručená pošta.mbox"
doveadm mailbox delete -u box@example.com "import/Odeslaná pošta.mbox"

NSF-to-mbox


Dopředu podotýkám, že Lotus Notes, stejně jako celé Domino, jsou naprosto příšerné produkty, které často nedodržují ani svoje vlastní proprietární nedokumentované standardy a mají velice mizernou a místy až nulovou kompatibilitu se standardy jakýmikoliv jinými. Navíc se nezřídka stává, že pokud jedna NSF databáze postupem času projde několika verzemi Lotus Notes, stejný typ dokumentů uvnitř stejné databáze se může lišit natolik, že si s nimi externí nástroje neporadí. Celkem reálně tedy hrozí, že několik mailovek budete muset stejně přetahovat ručně. Nenašel jsem žádný nativní linuxový nástroj zdarma, takže jsem ke konverzi použil nsf2x, který běží pouze na Windows s nainstalovaným Lotus Notes klientem, ze kterého pomocí Win32 COM API volá patřičné funkce. Je psaný v pythonu, ale v releasech se dá stáhnout i verze kompilovaná přímo pro Windows, takže nějaké veletoče s nastavováním pythonovského interpretu a závislostí balíčků nemusíte vůbec řešit. Jeho nastavení je také poměrně blbuvzdorné. Prostě se přihlásíte k lokální instanci Lotus Notes, ukážete mu složku s NSF soubory a složku pro export, kliknete na Convert a budete se modlit k velkému modrému božstvu, aby právě vás nestihla kletba nekompatibility. U velkých schránek trvá převod poměrně dlouho, takže v závislosti na velikosti a množství si zatím zajděte na kafe nebo filmový maraton Pána prstenů.

NSF2X

V případě, že vše proběhne dle očekávání, bude výsledkem opět adresář plný souborů v mbox formátu. Utilita nsf2x se však pokouší konvertovat i pravidla, kalendáře a všelijaké další věci, ve kterých nejsou maily a které doveadm nesežere, takže takové soubory můžete klidně ignorovat. No, a protože máme adresář se soubory ve formátu mbox, nahrajeme je na server a dále postupujeme podle příručky pro lov jelenů.

doveadm import -u box@example.com mbox:/tmp/box import all

doveadm move -u box@example.com "INBOX" mailbox "import/Inbox.mbox" all
doveadm move -u box@example.com "Odeslaná pošta" mailbox "import/Sent.mbox" all

doveadm mailbox delete -u box@example.com "import/Inbox.mbox"
doveadm mailbox delete -u box@example.com "import/Sent.mbox"

Na závěr doporučuju porovnat počty mailů v původním NSF a na dovecot serveru. Systémová hlášení (např. o nedoručitelnosti) a pozvánky se nekopírují, takže je pravděpodobné, že dovecot nahlásí o něco málo nižší počet, ale pokud v původní schránce bylo mailů 20 000 a po konverzi jich jsou jen 2000, bude celkem určitě něco špatně.

Další kousky s doveadm


Když už jsem se tak rozvášnil o užitečnosti rozhraní doveadm, odložím si do článku ještě pár dalších příkazů, které se v budoucnu mohou znova hodit.

Mazání zpráv od určitého stáří

Celkem užitečná záležitost pro nejrůznější koše, černé díry a jiná dočasná úložiště. Řádek níže jednoduše vymaže všechny zprávy z INBOXu, které do něj byly uloženy před více než 90 dny. Uložení nutně neimplikuje, že zpráva byla přijata před 90 dny. Mohla být v daném umístění pouze vytvořena nebo přesunuta odjinud.

doveadm expunge -u box@example.com mailbox % savedbefore 90d

Automatická archivace

Tenhle kousek už je trochu komplikovanější. Kdo někdy viděl takovou typický firemní mailbox, ani v nejmenším ho nepřekvapí INBOX o 50 000 mailech sahající do samotných počátků internetového věku. Lidi se pak diví, proč se jim mailoví klienti spouští deset minut. Skript níže vytvoří složky pro jednotlivé roky, v nich replikuje strukturu podsložek stejnou, jako mají INBOX a Odeslaná pošta (pokud vůbec nějakou mají) a maily starší 120 dní do takto vytvořených archivů přesune. Totéž se pokusí udělat i pro deset předchozích let.

#!/bin/bash

USER="box@example.com"
RETENTION=120
ARCHIVE_ROOT="Archiv"
BOXES_TO_ARCHIVE=("INBOX" "Odeslaná pošta")


# Load all existing subfolders in BOXES_TO_ARCHIVE
BOXES=()
IFS=$'\n'
for BOX in ${BOXES_TO_ARCHIVE[@]}; do
    BOXES+=($(doveadm mailbox list -u ${USER} ${BOX}*))
done

# Set range for mails in the year preceding RETENTION
BEFORE=$(date -d "-${RETENTION} days" "+%Y-%m-%d")
SINCE="${BEFORE:0:4}-01-01"
# Perform for the range above as well as last 10 years
for YEAR in $(seq ${BEFORE:0:4} -1 $((${BEFORE:0:4}-10))); do
    # Perform for all BOXES
    for BOX in ${BOXES[@]}; do
        # Check if there is anything to archive in BOX for period between BEFORE and SINCE
        if [ $(doveadm search -u ${USER} MAILBOX ${BOX} SENTBEFORE ${BEFORE} SENTSINCE ${SINCE} | wc -l) -gt 0 ]; then
            # Create and subscribe ARCHIVE subfolder if it doesn't exist
            ARCHIVE="${ARCHIVE_ROOT}/${YEAR}/${BOX}"
            doveadm mailbox status -u ${USER} messages ${ARCHIVE} >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                doveadm mailbox create -u ${USER} ${ARCHIVE}
                doveadm mailbox subscribe -u ${USER} ${ARCHIVE}
            fi
            # Move the mails to ARCHIVE subfolder
            doveadm move -u ${USER} ${ARCHIVE} mailbox ${BOX} SENTBEFORE ${BEFORE} SENTSINCE ${SINCE}
        fi
    done
    # Move on to previous year
    BEFORE="${YEAR}-01-01"
    SINCE="$((${YEAR}-1))-01-01"
done