Jaká je situace na trhu
Envelope je zbrusu nová knihovna pro posílání e-mailů v jazyce Python, což by mohlo leckoho překvapit a pobavit. Možná se i vy teď smějete, jaké kolo to vynalézáme! Vždyť dokument, který popisuje strukturu e-mailové zprávy, jak ji známe dnes, je RFC 822 Internet Message Format a pochází už z roku 1982. Za dvacet let následovaly další RFC 2822 (2001), RFC 5322 (2008) a nakonec aktuální RFC 6854 (2013). I zdrojový kód programů v Pythonu se rodí pod tlukotem klávesnic celého světa od roku 1991. Že by za tu dobu nevznikla řada knihoven pro posílání e-mailů? K čemu tedy další knihovna? Inu, pojďme se podívat, jaký je reálný výběr. Na oficiálním repozitáři PyPi po zadání hesla „email“ dostáváme osm tisíc výsledků. Většina z nich ale na první pohled ani nemá dokumentaci, jsou rozdělané a nedodělané, či dodělané, ale nedostatečné. Řada z nich je pak jednoúčelových, dobře vykonávají pouze část práce, kterou s odesláním máme. Zkusíme si tedy poradit sami. Brzy ovšem zjistíme, že řešení není zdaleka tak triviální, jak by se na první pohled mohlo zdát.
Šifrujeme vlastní silou
Pro vytvoření objektu e-mailu slouží standardní knihovna email
. Ta v poslední době zažila menší otřesení, když se od verze 3.6 doporučovaným objektem stala třída EmailMessage
, která zjednodušila tvoření objektu. Mnohem intuitivněji!
Vytvořme tedy objekt EmailMessage
a připravme ho na GPG šifrování. Zkonstruujeme objekt, nastavíme mu hlavičku Subject
a potom dvěma dalšími příkazy, které si musíme zapamatovat, složíme povinnou hlavičku Content-Type
.
python3
email = EmailMessage()
email["Subject"] = "Encrypted message"
email["To"] = "friend@examplecom"
email.set_type("multipart/encrypted")
email.set_param("protocol", "application/pgp-encrypted")
email.set_payload("hello")
Nyní náš objekt obsahuje tuto zprávu. Nebylo to nic těžkého, museli jsme si zapamatovat pár řádků. Stačí už jen e-mail poslat do schránky.
eml
Subject: Encrypted message
To: friend@examplecom
MIME-Version: 1.0
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"
hello
Jenže jak ho zašleme? Máme tady druhou jednoduchou standardní knihovnu smtplib
, která si povídá se SMTP serverem, který máte k dispozici. Do metody send_message
vložíme náš objekt a znovu zopakujeme příjemce v parametru to_addrs
, protože plánujeme příjemce v hlavičkách zašifrovat.
python3
smtp = smtplib.SMTP("localhost", 25)
if self.security == "starttls":
smtp.starttls()
smtp.login("uživatel", "heslo")
smtp.send_message(email, to_addrs="friend@examplecom")
Pozor past!
A sláva, zpráva je odeslána. Jenže ouha, není zašifrována, jak jsme původně chtěli. Jakže se tedy šifruje s GPG klíčem? Máme k dispozici několik knihoven, za pár desítek minut se rozhodneme, kterou použijeme. Knihovna gnupg
poskytuje elegantní interface k programu gpg
, jenž vlastní šifrování zajišťuje. Programátor ovšem potřebuje znalost, musí si prostudovat, jaké argumenty použít, co je to „trust model“, co je to jakýsi „text mode“ a jak se liší mód „inline“ vs „detached“. A když se mu přeci povede text zašifrovat a jásá, zbývá mu poslední krůček, převést šifrovaný text do e-mailu.
A zde už je slyšet šust tětivy a sklapne past. Tento malý poslední krůček, kterému programátor původně nepřikládal velký význam, nyní nabývá obrysu hydry. Shlíží na něj z RFC 3156, jež s robotí neúprosností popisuje, jak má struktura GPG šifrované zprávy vypadat: Ta nesestává pouze z hlaviček (jako je předmět), textu a horko těžko vložených příloh. Nestačí nám tento jediný objekt, potřebujeme jich vytvořit... šest:
Objekt 1 – vlastní e-mail: hlavičky, text, přílohy
Objekt 2 – šifrovaný předmět: text/rfc822-headers a v těle textu hlavička Subject
Objekt 3 – protected headers: obsahuje v přílohách první dva objekty
Objekt 4 – verze šifrování: přestože vždycky obsahuje konstantu "Version: 1", musí být přítomen
Objekt 5 – šifrovaný blob: application/octet stream, obsahuje v příloze šifrovaná data z objektu 3
Objekt 6 – PGP encrypted: obsahuje v příloze objekty 4 a 5 a tento jediný konečně posíláme
A v tomto okamžiku práce programátora končí, balí laptop a kleje, aby další den implementoval nešifrovanou zprávu, bez GPG podpisu nebo ó ty hrůzo šifrování. Prolistuje několik stránek, kde si ověří pochmurné podezření, že struktura zprávy šifrované se vehementně liší od struktury zprávy podepsané a ta je zase jiná než zpráva naráz podepsaná i šifrovaná. Když má zasílání e-mailů implementovat příště, raději zkopíruje své starší řešení, které už jakž takž fungovalo.
Svěřujeme se knihovně Envelope
Knihovna Envelope tvoří tenkou vrstvu nad několika dalšími knihovnami, které jsou sice elegantní a plní svůj účel, nepojí je však tmel. Tímto tmelem je výkřik programátorův: „Já chtěl jenom poslat e-mail!“ Tak běduje programátor, který si myslel, že půjde domů v pět odpoledne a dobré náladě. On je pak hlavní cílová skupina této knihovny, zaměřené na interface, aby programátor musel vědět co nejméně.
Celou anabázi s knihovnami email
, smtplib
a gnupg
zapíšeme jediným čitelným řádkem.
python3
envelope()
.message("hello")
.subject("Encrypted message")
.to("friend@examplecom")
.smtp("localhost", 25, "uživatel", "heslo", "starttls")
.encryption()
.send()
Přičemž motto „vědět co nejméně“ – to se týká i příloh. Dost zjišťování syntaxe. Stačí zavolat metodu attach
.
python3 .attach(file_contents, filename="attached-file.txt")
Nevíte, jestli přílohu vložit jako řetězec nebo byty? Je to jedno. Můžete ji vložit i jako cestu k souboru či standardní Path objekt. Nebo jako proud, který v Pythonu získáme výstupem z funkce open(filename)
. Cokoli máte k dispozici, vložte a Envelope se postará o zbytek.
Metody mají dynamický počet argumentů, co uživatel nezadá, snažíme se uhádnout (v případě příloh automaticky zjišťujeme MIME typ a vložíme inteligentní jméno souboru).
Knihovna doplní ke zprávě hlavičky jako Date a Message-ID, o nichž vám nikdo neřekne, že tam musí být, pokud nečtete RFC pozorně.
Důvěra uživatele
Knihovna Envelope nabízí transparentní možnosti otestování vlastní funkcionality. Programátor se totiž potřebuje spolehnout na to, co se děje pod pokličkou, a proto:
- Metoda
.send(False)
se zamítavým parametrem False vyhodnotí na pozadí veškerá data, ale místo aby e-mail zaslala, vypíše jeho přesně znění na obrazovku. - Metoda
preview()
pracuje podobně, vypíše však text v čitelné podobně. To jest nedotčený například quoted-printable kódováním, které se zapnulo ať už automaticky nebo na přání uživatele. Ani přílohy nevypisuje celé, pouze jejich shrnutí pro rychlý přehled. - Metoda
check()
ověří připojení k SMTP serveru a některé DNS mechanismy.
Vše je extenzivně dokumentováno a opatřeno příklady, protože příklady jsou často to jediné, podle čeho se rozhodujeme, kterou knihovnu vybrat. A protože to není všechno, dokumentace obsahuje složku s věcmi, týkající se mailu nepřímo, o které byste mohli škobrtnout. Neboť odeslat e-mail je věc jednoduchá, ve světě antispamfilterů, kdy je většina e-mailového provozu nežádoucí, je přijmout e-mail však něco docela jiného.
Co potřebuji vědět o DNS? A jak se to nastavuje?
Chcete poslat e-mail a nemáte SMTP server nebo nevíte, co to je? Buď hodinu vybírejte mezi dostupnými MTA (postfix, exim, sendmail)... nebo prostě testovací SMTP nainstalujte jediným řádkem z dokumentace.
Chcete začít šifrovat a nemáte ani ponětí, jak začít, natož klíč? Na jednom místě je krátký přehled rozdílů mezi S/MIME a GPG a krátkými tutoriály, jak testovací certifikát udělat. Snažíme se zvýšit bezpečnostní know-how.
Již za minutu u vás na počítači
Knihovnu Envelope můžete použít i jako samostatný program v příkazové řádce. To jsme ještě neřekli? Takhle by v bashi vypadal příkaz, kterým jsme před chvíli odeslali e-mail ze skriptu:
bash
envelope --message "hello" --subject "Encrypted message" --to "friend@examplecom" --smtp "localhost" 25 "uživatel" "heslo" "starttls" --encrypt --send
Knihovnu Envelope uživatelé Pythonu nainstalují nejsnáze pomocí standardního pip3 install envelope
, případně doplněné instalací externí závislosti swig
pomocí např. sudo apt install swig
, jak je uvedeno v sekci instalace. Homepage projektu s veškerou dokumentací naleznete na https://github.com/CZ-NIC/envelope/.
A pak už hurá šifrovat prostá data nebo posílat e-maily bezpečně, ať už pomocí GPG či S/MIME.
Edvard Rejthar
Autor článku pracuje jako vývojář a programátor ve sdružení CZ.NIC, správci české národní domény.