Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[python] Parsování emailu

1 view
Skip to first unread message

Jakub Vojáček

unread,
Apr 17, 2008, 10:21:39 AM4/17/08
to Konference PyCZ
Ahoj
 
Již podruhé během dvou dnů jsem se zasekl. Pracuji na takovém svém e-mailovém klientu. Můj problém spočívá v rozparsování emailu. K přijmu zpráv používám modul poplib. Ten vrací zprávy ve tvaru:
 
('+OK Message follows (1562 bytes).', ['Reply-To: =?iso-8859-2?Q?Jakub=20Voj=E1=E8ek?= <jak...@seznam.cz>', 'Received: from kubuvpocitac (r3ai164.net.upc.cz [213.220.226.164])', '\tby email-relay2.go.seznam.cz (Seznam SMTPD 1.0.36@12969) with ESMTP;', '\tWed, 16 Apr 2008 18:46:52 +0200 (CEST)  ', 'Message-Id: <004f01c89fe1$7b567220$6e7ba8c0@kubuvpocitac>', 'From: =?iso-8859-2?Q?Jakub=20Voj=E1=E8ek?= <jak...@seznam.cz>', 'To: jak...@seznam.cz', 'Subject: predemr', 'Date: Wed, 16 Apr 2008 18:46:52 +0200 (CEST)', 'Mime-Version: 1.0', 'Content-Type: multipart/alternative;', '\tboundary="----=_NextPart_000_004A_01C89FF2.3C51E080"', 'X-Priority: 3', 'X-Msmail-Priority: Normal', 'X-Mailer: Microsoft Outlook Express 6.00.2900.3138', 'X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3198', 'X-Smtpd: 1.0.36@12969', 'X-Seznam-User: jak...@seznam.cz', 'X-Qm-Mark: email-qm1<17546722>', 'X-Seznam-Ffp: 680759260', '', 'This is a multi-part message in MIME format.', '', '------=_NextPart_000_004A_01C89FF2.3C51E080', 'Content-Type: text/plain;', '\tcharset="iso-8859-2"', 'Content-Transfer-Encoding: quoted-printable', '', 'hhahsd', '------=_NextPart_000_004A_01C89FF2.3C51E080', 'Content-Type: text/html;', '\tcharset="iso-8859-2"', 'Content-Transfer-Encoding: quoted-printable', '', '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">', '<HTML><HEAD>', '<META http-equiv=3DContent-Type content=3D"text/html; =', 'charset=3Diso-8859-2">', '<META content=3D"MSHTML 6.00.2900.3314" name=3DGENERATOR>', '<STYLE></STYLE>', '</HEAD>', '<BODY bgColor=3D#ffffff>', '<DIV><FONT face=3DArial size=3D2>hhahsd</FONT></DIV></BODY></HTML>', '', '------=_NextPart_000_004A_01C89FF2.3C51E080--'], 1562)
 
Existuje nějaký modul, který by dovedl e-mail rozparsovat? V základní distribuci je modul email, který obsahuje funkci "email.message_from_string(r)". Tato funkce vrací všechno až na tu nejdůležitější věc: samotný obsah zpávy...
['Reply-To', 'Received', 'X-Spam-Checker-Version', 'X-Spam-Status', 'Received', 'Received', 'Received', 'Message-Id', 'From', 'To', 'Subject', 'Date', 'Mime-Version', 'Content-Type', 'X-Priority', 'X-Msmail-Priority', 'X-Mailer', 'X-Mimeole', 'X-Smtpd', 'X-Seznam-User', 'X-Smtpd', 'X-Nod32result', 'X-Seznam-Ffp']
 
Děkuji za každé postrčení...
 
Jakub Vojáček
 

Jan Kundrát

unread,
Apr 17, 2008, 10:29:19 AM4/17/08
to Konference PyCZ
Jakub Vojáček wrote:
> Děkuji za každé postrčení...

http://docs.python.org/lib/module-email.parser.html


Jakub Vojáček

unread,
Apr 17, 2008, 10:36:43 AM4/17/08
to Konference PyCZ
Jenomže to stejně nevrací tělo zprávy...

>>> Parser().parsestr(r).keys()


['Reply-To', 'Received', 'X-Spam-Checker-Version', 'X-Spam-Status',
'Received', 'Received', 'Received', 'Message-Id', 'From', 'To', 'Subject',
'Date', 'Mime-Version', 'Content-Type', 'X-Priority', 'X-Msmail-Priority',
'X-Mailer', 'X-Mimeole', 'X-Smtpd', 'X-Seznam-User', 'X-Smtpd',
'X-Nod32result', 'X-Seznam-Ffp']

http://docs.python.org/lib/module-email.parser.html


_______________________________________________
Python mailing list
Pyt...@py.cz
http://www.py.cz/mailman/listinfo/python

Jan Kundrát

unread,
Apr 17, 2008, 10:47:46 AM4/17/08
to Konference PyCZ
Jakub Vojáček wrote:
> Jenomže to stejně nevrací tělo zprávy...

Je dobre si prostudovat dokumentaci celeho modulu. Kdybys cetl [1],
dozvedel by ses, ze email.message.Message ma dve dulezite casti,
"headers" a "payload". Vic ti nereknu, myslim, ze na to uz umis prijit sam.

Pokud to s tim psanim mailoveho klienta myslis vazne, mel by sis precist
vic manualu.

[1] http://docs.python.org/lib/module-email.message.html

Hezky den,
-jkt

Jakub Vojáček

unread,
Apr 17, 2008, 11:37:31 AM4/17/08
to Konference PyCZ
Ano, už to částečně funguje. Manuál jsem četl a dokonce jsem zkoušel použít
funkci get_payload(), ale fakt mě nenapadlo, že to musím zavolat dvakrát...
Nicméně to funguje, nevím proč, pouze na některé emaily; zde je můj kód:

import re
from email.parser import*
m1="""('+OK Message follows (1562 bytes).', ['Reply-To:

m2="""('+OK Message follows (1601 bytes).', ['Reply-To:

=?iso-8859-2?Q?Jakub=20Voj=E1=E8ek?= <jak...@seznam.cz>', 'Received: from
kubuvpocitac (r3ai164.net.upc.cz [213.220.226.164])', '\tby

email-relay2.go.seznam.cz (Seznam SMTPD 1.0.36@12969) with ESMTP;', '\tThu,
17 Apr 2008 17:10:38 +0200 (CEST) ', 'Message-Id:
<00ba01c8a09d$320e0b70$6e7ba8c0@kubuvpocitac>', 'From:
=?iso-8859-2?Q?Jakub=20Voj=E1=E8ek?= <jak...@seznam.cz>', 'To:
jak...@seznam.cz', 'Subject: predemr', 'Date: Thu, 17 Apr 2008 17:10:36

+0200 (CEST)', 'Mime-Version: 1.0', 'Content-Type: multipart/alternative;',

'\tboundary="----=_NextPart_000_00B7_01C8A0AD.F44443C0"', 'X-Priority: 3',

'X-Msmail-Priority: Normal', 'X-Mailer: Microsoft Outlook Express
6.00.2900.3138', 'X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3198',
'X-Smtpd: 1.0.36@12969', 'X-Seznam-User: jak...@seznam.cz', 'X-Qm-Mark:

email-qm1<17566836>', 'X-Seznam-Ffp: -1361842557', '', 'This is a multi-part
message in MIME format.', '', '------=_NextPart_000_00B7_01C8A0AD.F44443C0',

'Content-Type: text/plain;', '\tcharset="iso-8859-2"',

'Content-Transfer-Encoding: quoted-printable', '', "'sdfdf','sdf'",
'------=_NextPart_000_00B7_01C8A0AD. F44443C0', 'Content-Type: text/html;',

'\tcharset="iso-8859-2"', 'Content-Transfer-Encoding: quoted-printable', '',
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">',

'<HTML><HEAD>', '<META http-equiv=3DContent-Type content=3 D"text/html; =',

'charset=3Diso-8859-2">', '<META content=3D"MSHTML 6.00.2900.33 14"
name=3DGENERATOR>', '<STYLE></STYLE>', '</HEAD>', '<BODY bgColor=3D#ffffff>'

, '<DIV><FONT face=3DArial =',
"size=3D2>'sdfdf','sdf'</FONT></DIV></BODY></HTML >", '',
'------=_NextPart_000_00B7_01C8A0AD.F44443C0--'], 1601)"""
m1=re.search(r"[\w]*\['(?P<x>[\w\W]*)'\]", m1).group("x").replace("',
'","\n")
m2=re.search(r"[\w]*\['(?P<x>[\w\W]*)'\]", m2).group("x").replace("',
'","\n")
print Parser().parsestr(m1).get_payload()[0].get_payload()
print Parser().parsestr(m2).get_payload()[0].get_payload()
#První email to rozparsuje dobře, ale ten druhý už ne...
#Děkuji za trpělivost; pomalu mi to myslí:(


----- Original Message -----
From: "Jan Kundrát" <j...@gentoo.org>
To: "Konference PyCZ" <pyt...@py.cz>
Sent: Thursday, April 17, 2008 4:47 PM
Subject: Re: [python] Parsování emailu

Jan Kundrát

unread,
Apr 18, 2008, 7:40:38 AM4/18/08
to Konference PyCZ
Jirka Vejrazka wrote:
> Pak uz jenom staci vedet (viz RFC 822 jestli se nepletu), ze oddelovacem
> mezi hlavickou mailu a telem mailu je prvni prazdna radka. Takze na
> zjisteni tela mailu nepotrebujes ani modul email, staci napsat pomerne
> jednoduchou funkci. Jejim parametrem jsou tvoje ukazkova data tak jak je
> vraci poplib, tj. jako tuple a ne jako string.

Tohle muze fungovat na jednoduche text/plain maily, ktere jeste navic
nebyly zakodovane necim jako base64. Pokud je cilem mailovy klient,
ktery umi precist i napriklad zpravu, ke ktere je prilozeny obrazek, a
nebo neco podobneho tomu, cos prave ted poslal ty, opravdu potrebujes
korektne pracovat s MIME formatovanim, jako to dela napriklad modul email.

Schvalne se zkus podivat na "zdrojovy kod" zpravy, kterous napsal,
nerekl bych, ze ji dokazes ocima precist...

Hezky den,
-jkt

Jirka Vejrazka

unread,
Apr 18, 2008, 8:26:35 AM4/18/08
to Konference PyCZ

Tohle muze fungovat na jednoduche text/plain maily, ktere jeste navic
nebyly zakodovane necim jako base64. Pokud je cilem mailovy klient,
ktery umi precist i napriklad zpravu, ke ktere je prilozeny obrazek, a
nebo neco podobneho tomu, cos prave ted poslal ty, opravdu potrebujes
korektne pracovat s MIME formatovanim, jako to dela napriklad modul email.

Schvalne se zkus podivat na "zdrojovy kod" zpravy, kterous napsal,
nerekl bych, ze ji dokazes ocima precist...


Ja vim, soutredil jsem se vcera na to abych puvodniho tazatele navedl na spravnou stopu, jak se dostat k telu mailu - evidentne se zamotal v tom jak se vubec vyhrabat ze zmeti znaku ktere se snazil zpracovavat jako string. O nic vic mi vcera neslo, dal jsem jenom navod jak rozumne ziskat "body" mailu. Nechtel jsem za nej psat cely zbytek emailoveho kliena ;-)

  Jirka

P.S. zrovna tuhle precist dokazu i v tom "raw" formatu :-)

Jakub Vojácek

unread,
Apr 18, 2008, 1:59:30 PM4/18/08
to Konference PyCZ
Dík. Jakmile jsem zjistil, že pop.retr vrací tuple, tak všechno už začalo fungovat.
Omlouvám se za ty zmatky, které jsem tady způsobil.
 
Jakub Vojáček

Jaroslav Lukesh

unread,
Apr 29, 2008, 1:59:55 PM4/29/08
to Konference PyCZ
Jak dlouho trvvá SQL nez vrátí data?

Osobne bych zavedl jeste dotaz pro vyzvednutí pouze hlavicek a body
vyzvednout samostatne pro kazdý mail. Stránkování lze resit na strane SQL
serveru, byt ne vzdy zcela snadno (treba MSSQL - tam je to opruz).

A samozrejme nastavit vhodne indexy nad sloupcema. Ale pokud

----- Original Message -----
From: Jakub Vojácek

Opet se na vás obracím s nekterými mými problémy. Tentokrát se jedná o
takovou spíse teoretickou otázku. Jiz mám naprogramovaného "relativne"
fungujícího postovního klienta (prijímání, psaní mailu, pravidla pro zprávy,
skupiny, kontakty, rss ctecka apod...). Pokud pracuji s databází, která
obsahuje 100 e-mailu, zádný problém nenastane, ale jelikoz e-maily nemazu,
tak je pocet e-mailu o neco vyssí (pres 4000). A v tom je práve ten problém.
Pokud mám napríklad slozku, ve které je 500 e-mailu, tak se nacítá asi 5
sekund. V jiných aplikacích (Outlook Express je tato doba 10 kratsí). A moje
otázka je: Jak by se tato doba dala zkrátit?
.....

Aby nacítání trvalo alespon o trochu méne, rozhodl jsem zavést stránkování
(na jedné strane pouze 100 mailu), ale moc jsem si nepomohl, protze stejne
musím procházet vsemi e-maily a zobrazovat pouze ty z daného rozsahu. Ve
funkci pridej_zaznam jeste musím získat odesílatele, predmet a cas prijetí,
coz zabere taky relativne dost casu.

Jakub Vojácek

unread,
Apr 29, 2008, 12:38:09 PM4/29/08
to Konference PyCZ
Ahoj
 
Opět se na vás obracím s některými mými problémy. Tentokrát se jedná o takovou spíše teoretickou otázku. Již mám naprogramovaného "relativně" fungujícího poštovního klienta (přijímání, psaní mailů, pravidla pro zprávy, skupiny, kontakty, rss čtečka apod...). Pokud pracuji s databází, která obsahuje 100 e-mailů, žádný problém nenastane, ale jelikož e-maily nemažu, tak je počet e-mailů o něco vyšší (přes 4000). A v tom je právě ten problém. Pokud mám například složku, ve které je 500 e-mailů, tak se načítá asi 5 sekund. V jiných aplikacích (Outlook Express je tato doba 10 kratší). A moje otázka je: Jak by se tato doba dala zkrátit?
Jako knihovnu pro tvorbu Gui používám WxPython a jako databázi, kam ukládám e-maily používám modul shelve. E-maily ukládám následovně:
 
def prijmi_email(self):
    email = pop.retr(x)
    email = "\n".join(email[1])
    kategorie = 0
    precteno = 0
    self.uloz_db(kategorie, [email, precteno])
def uloz_db(self, kategorie, email):
    s=shelve.open("Db/%s.db"%kategorie)
    id=s["id"]
    s[str(id)] = email
    s["id"] = id +1
    s.close()
    return id
 
Každý e-mail (v rámci jedné složky) má tedy svoje vlastní unikátní id. Načítání funguje následujícím způsobem:
 
def nacti_emaily(self, kategorie=0, strana = 0):
        self.listbox.DeleteAllItems()
        s=shelve.open("Db/%s.db"%kategorie)
        rozsah= []
        for x in range(strana*100, strana*100 + 100):
            rozsah.append(str(x))
        for prvek in s:
            if prvek == "id": continue
            if prvek in rozhrani:
                self.pridej_zaznam(s[prvek][0], prvek, precteny=s[prvek][1])
        s.close()
 
Aby načítání trvalo alespoň o trochu méně, rozhodl jsem zavést stránkování (na jedné straně pouze 100 mailů), ale moc jsem si nepomohl, protže stejně musím procházet všemi e-maily a zobrazovat pouze ty z daného rozsahu. Ve funkci pridej_zaznam ještě musím získat odesílatele, předmět a čas přijetí, což zabere taky relativně dost času.
Jak by se dal celý postup zefektivnit?
 
Děkuji za každou odpověď
 
Jakub Vojáček

Jirka Vejrazka

unread,
Apr 29, 2008, 2:20:55 PM4/29/08
to Konference PyCZ
Tak nevim, ale shelve se mi nezda nejvhodnejsi na vetsi mnozstvi data.
Muzu se ale plest, osobne jsem to nezkousel ani neznam zadna mereni.

Za vyzkouseni by stalo pouziti sqlite3. V pythonu 2.5 je jako modul,
do starsich se da doinstalovat.

Jirka Vejrazka

Jakub Vojáček

unread,
Apr 30, 2008, 10:17:47 AM4/30/08
to Konference PyCZ

> ------------ Původní zpráva ------------
> Od: Jirka Vejrazka <jirka.v...@gmail.com>
> Předmět: Re: [python] Parsování emailu
> Datum: 29.4.2008 20:21:22
> ----------------------------------------


Děkuji, je to o moc lepší. Nyní to zobrazí 2500 zpráv za 3 sekundy...

Blujacker

0 new messages