K doručování elektronických poštovních zpráv (emailů) je na Unixových poštovních serverech FIT a FEKT používán doručovací program (Mail Delivery Agent - MDA) Procmail. Procmail umožňuje příchozí emaily filtrovat libovolnými programy, ukládat do různých schránek (mailboxů), předávat na jiné adresy, apod. Procmail manipuluje s emaily na základě pravidel uložených v souboru $HOME/.procmailrc (proměnná $HOME je domácí adresář na příslušném UNIX serveru, FIT - eva, FEKT - fest). Pokud soubor .procmailrc v domácím adresáři není, procmail ukládá všechny příchozí emaily do souboru /var/mail/login (INBOX).

Poznámka: Přesměrování pošty pomocí souboru .forward zásadně nedoporučujeme, neboť může způsobit zacyklení doručování pošty.

Struktura emailu

Email se skládá z hlaviček a těla. Vlastní text emailu je uložen v těle. Hlavičky jsou skupina řádků na začátku emailu, které obsahují čitelné informace o emailu. Formát hlaviček je přesně definován (viz RFC 2076). Mnoho hlaviček je pouze informativních, některé mají význam i pro uživatele (např. Subject nebo From). Poštovní klienti běžně zobrazují pouze hlavičky určené pro uživatele. Každá hlavička začíná klíčovým slovem následovaným dvojtečkou (např. From:). Jednoduchý email může vypadat následovně:

Received: from eva.fit.vutbr.cz (eva.fit.vutbr.cz [147.229.10.14])
        by kazi.fit.vutbr.cz (envelope-from opicka@stud.fit.vutbr.cz) 
          (8.13.5/8.13.5) with ESMTP id j95Hf8Ri048770
          (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=OK)
        for <novak@fit.vutbr.cz>; Wed, 5 Oct 2005 19:41:08 +0200 (CEST)
Received: from PCB01.fit.vutbr.cz (PCB01.fit.vutbr.cz [147.229.176.41])
        by eva.fit.vutbr.cz (envelope-from opicka@stud.fit.vutbr.cz) 
          (8.13.4/8.13.3) with ESMTP id j95Hf5MX099093
        for <novak@fit.vutbr.cz>; Wed, 5 Oct 2005 19:41:05 +0200 (CEST)
Received: by PCB01.fit.vutbr.cz (Postfix, from userid 99999)
        id AAC6767A5; Wed,  5 Oct 2005 19:41:05 +0200 (CEST)
Message-ID: <20051005174105.GA4290@stud.fit.vutbr.cz>
From: "Jan Opicka" <opicka@fit.vutbr.cz>
To: <novak@fit.vutbr.cz>
Subject: Test
Date: Tue, 30 Mar 2004 10:35:47 +0200

Toto je tělo emailu.

Pravidla doručování pro procmail

Pravidla se skládají z příznaků (flags), podmínek (conditions) a řádku akce (action). Pravidlo má obecný tvar:

:0 [flags] [: [LockfileName] ]
žadná, jedna nebo více podmínek (každá podmínka na samostatném řádku)
požadovaná akce (jeden řádek)

Začátek pravidla

Každé pravidlo začíná :0. Za znakem nula mohou být uvedeny volby (flags). Je-li za znakem nula, resp. za příznaky uvedena dvojtečka, znamená to, že procmail má pro danou podmínku použít zamykací soubor. Jméno zamykacího souboru lze zadat za dvojtečkou. Není-li zadáno, procmail použije jméno souboru (schránky) uvedené na řádku akce nebo jméno souboru za prvním znakem > (soubor, do kterého bude přesměrován výstup externího programu), a na konec připojí obsah proměnné $LOCKEXT (implicitně .lock). Pokud nejde jméno zamykacího souboru odvodit, musí být zadáno. Zamykací soubor se vztahuje pouze k dané podmínce.

Zamykání je třeba nastavit při doručování do poštovní schránky (tedy zapisování do souboru) nebo jestliže je jako akce spuštěn externí program, který zapisuje do souboru. Při přeposílání emailu na jinou adresu (operátor !) zamykání není třeba a případné nastavení procmail ignoruje.

Jaký je význam zamykání? Procmail může být spuštěn při doručování několika dopisů vícekrát pro jednoho adresáta. Může se tak stát, že několik procesů chce současně zapisovat do stejného souboru (např. emailové schránky). Tím by ovšem došlo k promíchání obsahu emailů a k poškození schránky. Tento problém ošetřuje procmail tak, že první proces, který použije dané pravidlo vytvoří zamykací soubor. Když se jiný proces dostane na začátek stejného pravidla, pokusí se též vytvořit zamykací soubor. To se mu však nepovede, neboť zamykací soubor již existuje. Druhý proces pak čeká až první proces dokončí zpracování pravidla a smaže zamykací soubor.

Podmínky

Podmínky jsou nepovinné. Není-li uvedena ani jedna podmínka, je akce aplikována na všechny emaily. Je-li naopak uvedeno více podmínek (tj. více řádků s podmínkami), jsou jednotlivé podmínky spojeny logickým operátorem AND. Pak se akce provede pouze v případě, že jsou splněny (pravdivé) všechny podmínkové řádky.

* [oper]podmínka
... další řádky podmínek

Řádek podmínky musí začínat znakem '*'. Podmínky jsou rozšířené regulární výrazy kompatibilní s programem egrep(1). Kromě regulárních výrazů egrepu lze použít i další speciální testy, které jsou zvoleny některým z následujících znaků na začátku podmínky (oper):

!Negace podmínky.
?Testovat návratový kód zadaného programu.
<Porovnává, zda celková délka emailu je menší než zadané dekadické číslo.
>Porovnává, zda celková délka emailu je větší než zadané dekadické číslo.
var ??Porovnává podmínku oproti hodnotě proměnné prostředí var.

Implicitně jsou podmínky vyhodnocovány pouze pro hlavičky emailu. Zadáním příznaku B ve flags lze testovat tělo emailu. Lze kombinovat s příznakem H, pak se prohledávají hlavičky i tělo. Implicitně je při testování ignorován rozdíl mezi malými a velkými písmeny. Rozlišení lze zapnout příznakem D ve flags.

Akce

Řádek s akcí určuje, co se má s emailem provést v případě splnění všech podmínek. Chceme-li uložit dopis do určité schránky, uvedeme na řádku akce jméno poštovní schránky. V případě přeposílání emailu, začíná řádek s akcí vykřičníkem a za ním následuje adresa, na níž má být email přeposlán. Pro předání emailu externímu programu je třeba, aby řádek akce začínal znakem roura | (svislá čára).

Existují dva druhy pravidel - doručovací a nedoručovací. Jestliže je vykonáno doručovací pravidlo, procmail již nezpracovává další pravidla, email je považován za doručený. Toto chování lze změnit pomocí příznaku c. Doručovací pravidla jsou taková, která způsobí uložení emailu (nebo jeho hlavičky či těla) do souboru nebo jeho absorbování programem či přeposlání na jinou adresu. Po vykonání akce nedoručovacího pravidla procmail pokračuje zpracováním následujícího pravidla. Nedoručovací pravidla jsou taková, kde akce prožene email programem či filtrem, ale výstup je opět vrácen zpět do procmailu.

Jestliže podmínka v pravidle není splněna, pak akce není spuštěna (email není doručen) a procmail pokračuje následujícím pravidlem. Projde-li procmail již všechna pravidla v souboru .procmailrc (tj. nebyla provedena akce u žádného doručovacího pravidla), je email doručen do schránky definované proměnnou $DEFAULT. Proměnná $DEFAULT je na severech FEKT/FIT nastavena na /var/mail/login.

Příklad pravidla, které třídí emaily:

# Emaily od opicky do schranky opicka
:0:
* ^From: opicka@fit\.vutbr\.cz
mail/opicka

Popis:

  1. První řádek je komentář. Vše co následuje za znakem # až po znak konce řádku procmail považuje za komentář a tudíž ignoruje.
  2. Druhý řádek začíná :0, což označuje začátek pravidla. Dvojtečka za nulou říká, že se má použít zamykací soubor pro toto pravidlo.
  3. Třetí řádek začíná hvězdičkou což znamená, že se jedná o podmínku. Znak ^ je metaznak, který označuje začátek řádku. Znaky \ před tečkami říkají, že se jedná o znak tečka, nikoli o metaznak tečka, znamenající libovolný znak. Podmínka je splněna, je-li na začátku řádku řetězec From následovaný jednou mezerou, po níž následuje řetězec opicka@fit.vutbr.cz.
  4. Čtvrtý řádek je akce - uložení emailu do schránky (souboru) opicka v adresáři $HOME/mail.

Příklad pravidla pro přeposílání emailů na jiný server:

# nepřeposílat chyby
:0
* !^FROM_MAILER
! petr.novak@email.cz

Popis:

  1. Na prvním řádku je pouze :0, což označuje začátek pravidla bez použití zamykacího souboru (za 0 chybí druhá dvojtečka). Protože se jedná o přeposílání, nikoli o zápis do souboru (schránky), zamykací soubor není třeba a neměl by být použit.
  2. Druhý řádek začíná *, jedná se tedy o podmínku. Vzhledem ke znaku ! na začátku podmínky, je podmínka negovaná. FROM_MAILER není obyčejný řetězec, ale procmail jej nahradí komplikovaným regulárním výrazem (viz dále). Podmínka zajistí, že nebudou přeposlány emaily od démonů (poštovních serverů, z adres postmaster, daemon, mmdf, uucp, apod.). Pokud tuto podmínku neuvedete, může velice snadno dojít k nekonečnému zacyklení pošty: když nebude dopis na adresu 'petr.novak@email.cz' doručitelný, vrátí se vám zpět s oznámením o nedoručitelnosti. Pak se ovšem opět přepošle na adresu 'petr.novak@email.cz' a tak pořád dokola, dokud se nezaplní celý disk. Pokud budete používat přeposílání dopisů, nezapomeňte přidat do patřičného pravidla podmínku * !^FROM_MAILER.
  3. Třetí řádek je akce. Protože akce začíná znakem !, jedná se o přeposlání emailu na zadanou adresu.

Při tomto způsobu přesměrování jsou případné chyby doručení (plná schránka, příliš velká příloha, překlep v adrese) oznamovány zpět a odesilatel původního dopisu se o nich nedozví. Je proto vhodné schránku pravidelně kontrolovat.

Nebo je možné použít složitější pravidlo, které vrátí chybu původnímu odesilateli, ale ten se pak v případě chyby jednak dozví adresu, na kterou jste přeposílali, a zároveň ho zmate, že dostává chybu doručení na adresu, kterou nepoužil. A v případě, že posílal na více adres, neví, která to způsobila. Ale díky přidání hlavičky Resend-From při odesílání to znalý uživatel mailu najde v hlavičkách. (Teoreticky by se dalo přeposílat na adresu petr.novak+preposlano.z.xnova36.stud.fit.vutbr.cz@email.cz, ale přesto, že taková adresa je validní a např. gmail ji snese, seznam ji odmítne.)

# nepřeposílat chyby - pro jistotu
:0
* !^FROM_MAILER
{
  :0 h
  ODES=| formail -x Return-path

  :0
  |formail -a 'Resend-From: <xnovak9z@stud.fit.vut.cz>'|$SENDMAIL -oi -f "$ODES" novak@email.cz
}

Příznakem h dostane akce pouze hlavičky emailu (příznak b naopak zapne zpracování pouze těla). Speciální akce ve formátu VAR=| uloží standardní výstup následujícího příkazu do proměnné prostředí VAR.

Příklad pravidla pro přeposílání emailů na jiný server, ale email je současně uložen do schránky na lokálním serveru:

# neposílat chyby
:0 c
* !^FROM_MAILER
! petr.novak@email.cz

Použití příznaku c způsobí, že procmail neukončí provádění příkazového souboru .procmailrc po vykonání akce doručovacího pravidla, ale pokračuje dál. Nenajde-li ukončující pravidlo, uloží přeposlaný email do implicitní příchozí schránky.

Příklad pravidla pro přeposílání emailů na mobil jako SMS:

(Pozn.: určeno jen pro odvážné, jakékoli finanční i jiné následky nelze reklamovat a požadovat náhradu škod)
:0
# neposílat chyby
* !^FROM_MAILER
# na mobil jen malé dopisy
* < 1000
! petr.novak@sms.oscar.cz

Pravidlo je obdobné předchozímu. Navíc je zde pouze podmínkový řádek < 1000, který zabrání přeposílání emailů delších než 1000 znaků.

Regulární výrazy (RE)

Nejjednodušším regulárním výrazem je jeden znak nebo řetězec znaků. Složitější regulární výrazy obsahují metaznaky s tímto významem:

Metaznak Význam v regulárním výrazu
.Libovolný znak kromě znaku nový řádek.
*Libovolný (i nulový) počet opakování výskytu předchozího znaku nebo položky.
?Žádný nebo jeden výskyt předchozího znaku (položky).
+Minimálně jeden výskyt předchozího znaku (položky).
^Začátek řádku.
$Konec řádku.
[seznam znaků]Libovolný jeden znak ze seznamu.
[^seznam znaků]Libovolný jeden znak kromě znaků uvedených v seznamu.
(řetězec)Řetězec je považován za jednu položku.
|OR. Např. (abc|cde) znamená buď řetězec abc nebo cde.
\<řetězec\>Začátek nebo konec slova. Slovo je řetězec obsahující pouze písmena, číslice a podtržítka. Ostatní znaky slovo ohraničují (vymezují).
\metaznakZpětné lomítko vypíná funkci metaznaku. Např. \. má význam normální tečky nikoli "zpětného lomítka následovaného libovolným znakem". Neplatí však pro znak <, jehož speciální význam je třeba potlačit jiným způsobem.
\nový řádekVýraz pokračuje i na následujícím řádku. Znaky mezera na začátku následujícího řádku jsou ignorovány.

Přílady regulárních výrazů:

a*Libovolný počet opakování znaku a (i nulový).
a+Jeden nebo více znaků a.
a?Žádný nebo jeden znak a.
[abuv12]Libovolný ze znaků a,b,u,v,1,2.
[0-9]Číslice.
[^abx12]Libovolný znak kromě a,b,x,1,2
[^-a-d]Libovolný znak, který není pomlčka, nebo písmeno a,b,c,d
de|abcBuď řetězec 'de' nebo 'abc'.
(abc)*Nulové nebo vícenásobné opakování řetězce 'abc'.

Vnitřní proměnné procmailu H a B

Proměnná prostředí H obsahuje hlavičky (headers) emailu, zatímco proměnná B obsahuje tělo (body).

Příklad použití:

:0:
* H ?? ^Subject:.*money
* B ?? call toll free
mail/smeti

Podmínka ?? hledá v obsahu uvedené proměnné řetězec popsaný regulárním výrazem. Pravidlo ukládá do schránky smeti emaily, jejichž hlavička Předmět obsahuje řetězec 'money' a zároveň se v jejich těle se vyskytuje řetězec 'call toll free'.

Speciální význam řetězců ^TO_, ^FROM_DAEMON, ^FROM_MAILER

Výše uvedené řetězce mají význam maker, které procmail nahrazuje poměrně komplikovanými regulárními výrazy. Řetězec ^TO_ (obě písmena velká !) by vybírá hlavičky obsahující adresu cíle emailu. Typicky jde o hlavičky To, Cc, Resent-To. Řetězec ^FROM_DEAMON vybírá zprávy od většiny démonů a řetězec ^FROM_MAILER vybírá zprávy od většiny poštovních serverů.

^TO_ je nahrazeno:

(^((Original-)?(Resent-)?(To |Cc |Bcc) |(X-Envelope |Apparently(-Resent)?)-To)
:(.*[^-a-zA-Z0-9_.])?)

Hledá hlavičku, která začíná To, Cc, Resent-To, nebo jinou specifikací cíle, následuje znak :, libovolný počet znaků (i nulový) a může následovat emailová adresa, která začíná řetězcem s počátečním znakem -a-zA-Z0-9_..

^FROM_DEAMON je nahrazeno:

(^(Mailing-List : |Precedence :.*(junk |bulk |list) |
To : Multiple recipients of |(((Resent-)?(From |Sender) |X-Envelope-From) : |
>?From )([^>]*[^(.%@a-z0-9])?(Post(ma?(st(e?r)? |n) |office) |(send)?Mail(er)? |
daemon |m(mdf |ajordomo) |n?uucp |LIST(SERV |proc) |NETSERV |o(wner |ps) |
r(e(quest |sponse) |oot) |b(ounce |bs\.smtp) |echo |mirror |s(erv(ices? |er) |
mtp(error)? |ystem) |A(dmin(istrator)? |MMGR |utoanswer))
(([^).! :a-z0-9][-_a-z0-9]*)?[%@>\t ][^<)]*(\(.*\).*)?)?$([^>] |$)))

^FROM_MAILER je nahrazeno:

(^(((Resent-)?(From |Sender) |X-Envelope-From) : |
>?From )([^>]*[^(.%@a-z0-9])?(Post(ma(st(er)? |n) |office) |(send)?Mail(er)? |
daemon |mmdf |n?uucp |ops |r(esponse |oot) |(bbs\.)?smtp(error)? |
s(erv(ices? |er) |ystem) |A(dmin(istrator)? |MMGR))
(([^).! :a-z0-9][-_a-z0-9]*)?[%@>\t ][^<)]*(\(.*\).*)?)?$([^>] |$))

Odkazy na informace o programu procmail

Další podrobnosti o souboru procmailrc lze získat z manuálových stránek man procmailrc. Příklady pravidel lze nalézt v man procmailex. Pro podrobné seznámení se s funkcí programu procmail a psaním pravidel lze doporučit Proctut: Procmail Tutorials nebo Nancy McGough's "Procmail Quick Start".

Je program procmail stále bezpečný?

Program procmail již není dále aktivně vyvíjen. Všechny známé potenciální bezpečnostní problémy (CVE) jsou ale v používané verzi opraveny.

Zpět na návody CVT

Připomínky k této stránce zasílejte na adresu lampa@fit.vutbr.cz
Nahoru