Apgūstiet Python 'email' pakotni. Uzziniet, kā efektīvi un globāli izveidot sarežģītus MIME ziņojumus un parsēt ienākošos e-pastus datu ieguvei.
Python "email" pakotnes apgūšana: MIME ziņojumu izveides un noturīgas parsēšanas māksla
E-pasts joprojām ir globālās komunikācijas stūrakmens, neaizstājams personiskai sarakstei, biznesa operācijām un automatizētām sistēmas paziņojumiem. Aiz katra bagātināta teksta e-pasta, katra pielikuma un katra rūpīgi formatēta paraksta slēpjas daudzpusīgu interneta pasta paplašinājumu (MIME) sarežģītība. Izstrādātājiem, īpaši tiem, kas strādā ar Python, ir kritiska prasme apgūt, kā programmatiski veidot un parsēt šos MIME ziņojumus.
Python iebūvētā email
pakotne nodrošina noturīgu un visaptverošu sistēmu e-pasta ziņojumu apstrādei. Tā nav paredzēta tikai vienkārša teksta sūtīšanai; tā ir izstrādāta, lai abstrahētos no sarežģītajām MIME detaļām, ļaujot jums ar ievērojamu precizitāti izveidot sarežģītus e-pastus un iegūt konkrētus datus no ienākošajiem. Šis ceļvedis jūs dziļi iepazīstinās ar diviem galvenajiem šīs pakotnes aspektiem: MIME ziņojumu izveide sūtīšanai un to parsēšana datu ieguvei, sniedzot globālu skatījumu uz labāko praksi.
Izpratne par izveidi un parsēšanu ir būtiska. Kad jūs veidojat ziņojumu, jūs būtībā definējat tā struktūru un saturu, lai cita sistēma to interpretētu. Kad jūs parsējat, jūs interpretējat struktūru un saturu, ko definējusi cita sistēma. Dziļa izpratne par vienu ievērojami palīdz apgūt otru, tādējādi radot noturīgākas un savietojamākas e-pasta lietojumprogrammas.
MIME izpratne: mūsdienu e-pasta pamats
Pirms iedziļināties Python specifikā, ir svarīgi saprast, kas ir MIME un kāpēc tas ir tik būtisks. Sākotnēji e-pasta ziņojumi bija ierobežoti ar vienkāršu tekstu (7 bitu ASCII rakstzīmes). MIME, kas tika ieviests 90. gadu sākumā, paplašināja e-pasta iespējas, lai atbalstītu:
- Ne-ASCII rakstzīmes: Ļaujot izmantot tekstu tādās valodās kā arābu, ķīniešu, krievu vai jebkurā citā valodā, kas izmanto rakstzīmes ārpus ASCII kopas.
- Pielikumi: Failu, piemēram, dokumentu, attēlu, audio un video, sūtīšana.
- Bagātināta teksta formatēšana: HTML e-pasti ar treknrakstu, slīprakstu, krāsām un izkārtojumiem.
- Vairākas daļas: Vienkārša teksta, HTML un pielikumu apvienošana vienā e-pastā.
MIME to panāk, pievienojot e-pasta ziņojumam specifiskas galvenes un strukturējot tā pamattekstu dažādās "daļās". Galvenās MIME galvenes, ar kurām jūs saskarsieties, ietver:
Content-Type:
Norāda datu tipu daļā (piemēram,text/plain
,text/html
,image/jpeg
,application/pdf
,multipart/alternative
). Tas bieži ietver arī parametrucharset
(piemēram,charset=utf-8
).Content-Transfer-Encoding:
Norāda, kā e-pasta klientam jāatkodē saturs (piemēram,base64
bināriem datiem,quoted-printable
galvenokārt tekstam ar dažām ne-ASCII rakstzīmēm).Content-Disposition:
Ieteic, kā saņēmēja e-pasta klientam jārāda daļa (piemēram,inline
rādīšanai ziņojuma pamattekstā,attachment
saglabājamam failam).
Python email
pakotne: padziļināts ieskats
Python email
pakotne ir visaptveroša bibliotēka, kas paredzēta e-pasta ziņojumu programmatiskai izveidei, parsēšanai un modificēšanai. Tā ir veidota ap Message
objektiem, kas attēlo e-pasta struktūru.
Galvenie moduļi pakotnē ietver:
email.message:
Satur galvenoEmailMessage
klasi, kas ir primārā saskarne e-pasta ziņojumu izveidei un manipulēšanai. Tā ir ļoti elastīga klase, kas automātiski apstrādā MIME detaļas.email.mime:
Nodrošina mantotas klases (piemēram,MIMEText
,MIMEMultipart
), kas piedāvā precīzāku kontroli pār MIME struktūru. Lai ganEmailMessage
parasti ir vēlama jaunam kodam tās vienkāršības dēļ, šo klašu izpratne var būt noderīga.email.parser:
Piedāvā tādas klases kāBytesParser
unParser
, lai konvertētu neapstrādātus e-pasta datus (baitus vai virknes) parEmailMessage
objektiem.email.policy:
Definē politikas, kas kontrolē, kā tiek veidoti un parsēti e-pasta ziņojumi, ietekmējot galvenes kodēšanu, rindu beigas un kļūdu apstrādi.
Vairumā mūsdienu lietojumu gadījumu jūs galvenokārt mijiedarbosities ar email.message.EmailMessage
klasi gan izveidei, gan parsēta ziņojuma objektam. Tās metodes ievērojami vienkāršo to, kas agrāk bija daudz garāks process ar mantotajām email.mime
klasēm.
MIME ziņojumu izveide: e-pastu veidošana ar precizitāti
E-pastu veidošana ietver dažādu komponentu (teksta, HTML, pielikumu) apvienošanu derīgā MIME struktūrā. Klase EmailMessage
ievērojami racionalizē šo procesu.
Pamata teksta e-pasti
Vienkāršākais e-pasts ir vienkāršs teksts. Jūs varat izveidot to un bez piepūles iestatīt pamata galvenes:
from email.message import EmailMessage
msg = EmailMessage()
msg['Subject'] = 'Greetings from Python'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
msg.set_content('Sveiki, šis ir vienkāršs teksta e-pasts, kas nosūtīts no Python.\n\nAr cieņu,\nJūsu Python skripts')
print(msg.as_string())
Paskaidrojums:
EmailMessage()
izveido tukšu ziņojuma objektu.- Vārdnīcai līdzīga piekļuve (
msg['Subject'] = ...
) iestata kopējās galvenes. set_content()
pievieno e-pasta primāro saturu. Pēc noklusējuma tas secinaContent-Type: text/plain; charset="utf-8"
.as_string()
serializē ziņojumu virknes formātā, kas piemērots sūtīšanai, izmantojot SMTP vai saglabāšanai failā.
HTML satura pievienošana
Lai nosūtītu HTML e-pastu, vienkārši norādiet satura tipu, izsaucot set_content()
. Ir laba prakse nodrošināt vienkārša teksta alternatīvu saņēmējiem, kuru e-pasta klienti neatveido HTML, vai pieejamības apsvērumu dēļ.
from email.message import EmailMessage
msg = EmailMessage()
msg['Subject'] = 'Jūsu HTML biļetens'
msg['From'] = 'newsletter@example.com'
msg['To'] = 'subscriber@example.com'
html_content = """
<html>
<head></head>
<body>
<h1>Laipni lūgti mūsu globālajā atjauninājumā!</h1>
<p>Cienījamais abonente!</p>
<p>Šis ir jūsu <strong>jaunākais atjauninājums</strong> no visas pasaules.</p>
<p>Apmeklējiet mūsu <a href="http://www.example.com">vietni</a>, lai uzzinātu vairāk.</p>
<p>Ar cieņu,<br>Komanda</p>
</body>
</html>
"""
# Pievienojiet HTML versiju
msg.add_alternative(html_content, subtype='html')
# Pievienojiet vienkārša teksta alternatīvu
plain_text_content = (
"Laipni lūgti mūsu globālajā atjauninājumā!\n\n"
"Cienījamais abonente!\n\n"
"Šis ir jūsu jaunākais atjauninājums no visas pasaules.\n"
"Apmeklējiet mūsu vietni, lai uzzinātu vairāk: http://www.example.com\n\n"
"Ar cieņu,\nKomanda"
)
msg.add_alternative(plain_text_content, subtype='plain')
print(msg.as_string())
Paskaidrojums:
add_alternative()
tiek izmantota, lai pievienotu dažādus *tā paša* satura attēlojumus. E-pasta klients parādīs "labāko", ko tas spēj apstrādāt (parasti HTML).- Tas automātiski izveido
multipart/alternative
MIME struktūru.
Pielikumu apstrāde
Failu pievienošana ir vienkārša, izmantojot add_attachment()
. Jūs varat pievienot jebkura veida failu, un pakotne apstrādā atbilstošos MIME tipus un kodējumus (parasti base64
).
from email.message import EmailMessage
from pathlib import Path
# Create dummy files for demonstration
Path('report.pdf').write_bytes(b'%PDF-1.4\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n2 0 obj<</Count 0>>endobj\nxref\n0 3\n0000000000 65535 f\n0000000009 00000 n\n0000000052 00000 n\ntrailer<</Size 3/Root 1 0 R>>startxref\n104\n%%EOF') # A very basic, invalid PDF placeholder
Path('logo.png').write_bytes(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\x0cIDAT\x08\x99c`\x00\x00\x00\x02\x00\x01\xe2!\x00\xa0\x00\x00\x00\x00IEND\xaeB`\x82') # A 1x1 transparent PNG placeholder
msg = EmailMessage()
msg['Subject'] = 'Svarīgs dokuments un attēls'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
msg.set_content('Lūdzu, atrodiet pievienoto ziņojumu un uzņēmuma logotipu.')
# Pievienojiet PDF failu
with open('report.pdf', 'rb') as f:
file_data = f.read()
msg.add_attachment(
file_data,
maintype='application',
subtype='pdf',
filename='Annual_Report_2024.pdf'
)
# Pievienojiet attēla failu
with open('logo.png', 'rb') as f:
image_data = f.read()
msg.add_attachment(
image_data,
maintype='image',
subtype='png',
filename='CompanyLogo.png'
)
print(msg.as_string())
# Clean up dummy files
Path('report.pdf').unlink()
Path('logo.png').unlink()
Paskaidrojums:
add_attachment()
pieņem faila satura neapstrādātus baitus.maintype
unsubtype
norāda MIME tipu (piemēram,application/pdf
,image/png
). Tie ir būtiski, lai saņēmēja e-pasta klients pareizi identificētu un apstrādātu pielikumu.filename
nodrošina nosaukumu, ar kuru saņēmējs saglabās pielikumu.- Tas automātiski iestata
multipart/mixed
struktūru.
Daudzdaļīgu ziņojumu izveide
Ja jums ir ziņojums ar HTML pamattekstu, vienkārša teksta alternatīvu un iekļautiem attēliem vai saistītiem failiem, jums ir nepieciešama sarežģītāka daudzdaļīga struktūra. Klase EmailMessage
to apstrādā gudri, izmantojot add_related()
un add_alternative()
.
Bieži sastopams scenārijs ir HTML e-pasts ar attēlu, kas iegults tieši HTML (iekļauts attēls). Tas izmanto multipart/related
.
from email.message import EmailMessage
from pathlib import Path
# Create a dummy image file for demonstration (a 1x1 transparent PNG)
Path('banner.png').write_bytes(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\x0cIDAT\x08\x99c`\x00\x00\x00\x02\x00\x01\xe2!\x00\xa0\x00\x00\x00\x00IEND\xaeB`\x82')
msg = EmailMessage()
msg['Subject'] = 'Iekļautā attēla piemērs'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
# Vienkārša teksta versija (alternatīva)
plain_text = 'Apskatiet mūsu apbrīnojamo reklāmkarogu!\n\n[Attēls: Banner.png]\n\nApmeklējiet mūsu vietni.'
msg.set_content(plain_text, subtype='plain') # Iestatīt sākotnējo vienkārša teksta saturu
# HTML versija (ar CID iekļautajam attēlam)
html_content = """
<html>
<head></head>
<body>
<h1>Mūsu jaunākais piedāvājums!</h1>
<p>Cienījamais klient!</p>
<p>Nepalaidiet garām mūsu īpašo globālo akciju:</p>
<img src="cid:my-banner-image" alt="Promotion Banner">
<p>Noklikšķiniet <a href="http://www.example.com">šeit</a>, lai uzzinātu vairāk.</p>
</body>
</html>
"""
msg.add_alternative(html_content, subtype='html') # Pievienojiet HTML alternatīvu
# Pievienojiet iekļauto attēlu (saistīto saturu)
with open('banner.png', 'rb') as img_file:
image_data = img_file.read()
msg.add_related(
image_data,
maintype='image',
subtype='png',
cid='my-banner-image' # Šis CID atbilst 'src' HTML
)
print(msg.as_string())
# Clean up dummy file
Path('banner.png').unlink()
Paskaidrojums:
set_content()
nosaka sākotnējo saturu (šeit, vienkāršu tekstu).add_alternative()
pievieno HTML versiju, izveidojotmultipart/alternative
struktūru, kas satur vienkārša teksta un HTML daļas.add_related()
tiek izmantota saturam, kas ir "saistīts" ar kādu no ziņojuma daļām, parasti iekļautajiem attēliem HTML. Tas pieņemcid
(Content-ID) parametru, kas pēc tam tiek atsauces HTML tagā<img src="cid:my-banner-image">
.- Galīgā struktūra būs
multipart/mixed
(ja bija ārējie pielikumi), kas saturmultipart/alternative
daļu, kura savukārt saturmultipart/related
daļu.multipart/related
daļa satur HTML un iekļauto attēlu. KlaseEmailMessage
apstrādā šo ligzdošanas sarežģītību jūsu vietā.
Kodēšana un rakstzīmju kopas globālai sasniedzamībai
Starptautiskajai komunikācijai pareiza rakstzīmju kodēšana ir vissvarīgākā. Klase email
pēc noklusējuma stingri atbalsta UTF-8 izmantošanu, kas ir universāls standarts dažādu rakstzīmju kopu apstrādei no visas pasaules.
from email.message import EmailMessage
msg = EmailMessage()
msg['Subject'] = 'Globālās rakstzīmes: こんにちは, Привет, नमस्ते'
msg['From'] = 'global_sender@example.com'
msg['To'] = 'global_recipient@example.com'
# Japanese, Russian, and Hindi characters
content = "Šis ziņojums satur dažādas globālās rakstzīmes:\n"
content += "こんにちは (Japāņu)\n"
content += "Привет (Krievu)\n"
content += "नमस्ते (Hindi)\n\n"
content += "Pakotne 'email' graciozi apstrādā UTF-8."
msg.set_content(content)
print(msg.as_string())
Paskaidrojums:
- Kad
set_content()
saņem Python virkni, tā automātiski kodē to uz UTF-8 un iestata galveniContent-Type: text/plain; charset="utf-8"
. - Ja saturs to prasa (piemēram, satur daudzas ne-ASCII rakstzīmes), tā var arī piemērot
Content-Transfer-Encoding: quoted-printable
vaibase64
, lai nodrošinātu drošu pārsūtīšanu vecākās e-pasta sistēmās. Pakotne to apstrādā automātiski saskaņā ar izvēlēto politiku.
Pielāgotas galvenes un politikas
Jūs varat pievienot jebkuru pielāgotu galveni e-pastam. Politikas (no email.policy
) definē, kā tiek apstrādāti ziņojumi, ietekmējot tādus aspektus kā galvenes kodēšana, rindu beigas un kļūdu apstrāde. Noklusējuma politika parasti ir laba, taču jūs varat izvēlēties SMTP
stingrai SMTP atbilstībai vai definēt pielāgotas.
from email.message import EmailMessage
from email import policy
msg = EmailMessage(policy=policy.SMTP)
msg['Subject'] = 'E-pasts ar pielāgotu galveni'
msg['From'] = 'info@example.org'
msg['To'] = 'user@example.org'
msg['X-Custom-Header'] = 'Šī ir pielāgota vērtība izsekošanai'
msg['Reply-To'] = 'support@example.org'
msg.set_content('Šis e-pasts demonstrē pielāgotas galvenes un politikas.')
print(msg.as_string())
Paskaidrojums:
- Izmantojot
policy=policy.SMTP
, tiek nodrošināta stingra atbilstība SMTP standartiem, kas var būt kritiski piegādei. - Pielāgotas galvenes tiek pievienotas tāpat kā standarta galvenes. Tās bieži sākas ar
X-
, lai apzīmētu nestandarta galvenes.
MIME ziņojumu parsēšana: informācijas iegūšana no ienākošajiem e-pastiem
Parsēšana ietver neapstrādātu e-pasta datu (parasti saņemti, izmantojot IMAP vai no faila) pārvēršanu par EmailMessage
objektu, ko pēc tam var viegli pārbaudīt un manipulēt.
Ielāde un sākotnējā parsēšana
Jūs parasti saņemsiet e-pastus kā neapstrādātus baitus. Šim nolūkam tiek izmantots email.parser.BytesParser
(vai ērtības funkcijas email.message_from_bytes()
).
from email.parser import BytesParser
from email.policy import default
raw_email_bytes = b"""
From: sender@example.com
To: recipient@example.com
Subject: Test Email with Basic Headers
Date: Mon, 1 Jan 2024 10:00:00 +0000
Content-Type: text/plain; charset="utf-8"
This is the body of the email.
It's a simple test.
"""
# Izmantojot BytesParser
parser = BytesParser(policy=default)
msg = parser.parsebytes(raw_email_bytes)
# Vai izmantojot ērtības funkciju
# from email import message_from_bytes
# msg = message_from_bytes(raw_email_bytes, policy=default)
print(f"Temats: {msg['subject']}")
print(f"No: {msg['from']}")
print(f"Satura veids: {msg['Content-Type']}")
Paskaidrojums:
BytesParser
pieņem neapstrādātus baitu datus (kā e-pasti tiek pārsūtīti) un atgriežEmailMessage
objektu.policy=default
norāda parsēšanas noteikumus.
Piekļuve galvenēm
Galvenes ir viegli pieejamas, izmantojot vārdnīcai līdzīgas atslēgas. Pakotne automātiski apstrādā kodēto galveņu dekodēšanu (piemēram, temati ar starptautiskām rakstzīmēm).
# ... (izmantojot 'msg' objektu no iepriekšējā parsēšanas piemēra)
print(f"Datums: {msg['date']}")
print(f"Ziņojuma ID: {msg['Message-ID'] if 'Message-ID' in msg else 'N/A'}")
# Vairāku galveņu apstrāde (piemēram, 'Received' galvenes)
# from email.message import EmailMessage # Ja vēl nav importēts
# from email import message_from_string # Ātram virknes piemēram
multi_header_email = message_from_string(
"""
From: a@example.com
To: b@example.com
Subject: Multi-header Test
Received: from client.example.com (client.example.com [192.168.1.100])
by server.example.com (Postfix) with ESMTP id 123456789
for <b@example.com>; Mon, 1 Jan 2024 10:00:00 +0000 (GMT)
Received: from mx.another.com (mx.another.com [192.168.1.101])
by server.example.com (Postfix) with ESMTP id 987654321
for <b@example.com>; Mon, 1 Jan 2024 09:59:00 +0000 (GMT)
Body content here.
"""
)
received_headers = multi_header_email.get_all('received')
if received_headers:
print("\nSaņemtās galvenes:")
for header in received_headers:
print(f"- {header}")
Paskaidrojums:
- Piekļūstot galvenei, tā atgriež tās vērtību kā virkni.
get_all('header-name')
ir noderīga galvenēm, kas var parādīties vairākas reizes (piemēram,Received
).- Pakotne apstrādā galveņu dekodēšanu, tāpēc vērtības, piemēram,
Subject: =?utf-8?Q?Global_Characters:_=E3=81=93=E3=82=93=E3=81=AB=E3=81=A1=E3=81=AF?=
, tiek automātiski pārvērstas lasāmos virknēs.
Pamatteksta satura iegūšana
Faktiskā ziņojuma pamatteksta iegūšanai ir jāpārbauda, vai ziņojums ir daudzdaļīgs. Daudzdaļīgu ziņojumu gadījumā jūs veicat iterāciju cauri tā daļām.
from email.message import EmailMessage
from email import message_from_string
multipart_email_raw = """
From: multi@example.com
To: user@example.com
Subject: Test Multipart Email
Content-Type: multipart/alternative; boundary="_----------=_12345"
--_----------=_12345
Content-Type: text/plain; charset="utf-8"
Sveiki no vienkāršā teksta daļas!
--_----------=_12345
Content-Type: text/html; charset="utf-8"
<html>
<body>
<h1>Sveiki no HTML daļas!</h1>
<p>Šis ir <strong>bagātināta teksta</strong> e-pasts.</p>
</body>
</html>
--_----------=_12345--
"""
msg = message_from_string(multipart_email_raw)
if msg.is_multipart():
print("\n--- Daudzdaļīga e-pasta pamatteksts ---")
for part in msg.iter_parts():
content_type = part.get_content_type()
charset = part.get_content_charset() or 'utf-8' # Noklusējums uz utf-8, ja nav norādīts
payload = part.get_payload(decode=True) # Dekodēt pamatteksta baitus
try:
decoded_content = payload.decode(charset)
print(f"Satura veids: {content_type}, Rakstzīmju kopa: {charset}\nSaturs:\n{decoded_content}\n")
except UnicodeDecodeError:
print(f"Satura veids: {content_type}, Rakstzīmju kopa: {charset}\nSaturs: (Binārie vai neatkodējamie dati)\n")
# Apstrādāt bināros datus vai mēģināt atgriezenisko kodēšanu
else:
print("\n--- Vienas daļas e-pasta pamatteksts ---")
charset = msg.get_content_charset() or 'utf-8'
payload = msg.get_payload(decode=True)
try:
decoded_content = payload.decode(charset)
print(f"Satura veids: {msg.get_content_type()}, Rakstzīmju kopa: {charset}\nSaturs:\n{decoded_content}\n")
except UnicodeDecodeError:
print(f"Saturs: (Binārie vai neatkodējamie dati)\n")
Paskaidrojums:
is_multipart()
nosaka, vai e-pastam ir vairākas daļas.iter_parts()
veic iterāciju cauri visām daudzdaļīga ziņojuma apakšdaļām.get_content_type()
atgriež pilno MIME tipu (piemēram,text/plain
).get_content_charset()
iegūst rakstzīmju kopu noContent-Type
galvenes.get_payload(decode=True)
ir izšķirošs: tas atgriež *dekodēto* saturu kā baitus. Pēc tam jums ir jāizdara.decode()
šiem baitiem, izmantojot pareizo rakstzīmju kopu, lai iegūtu Python virkni.
Pielikumu apstrāde parsēšanas laikā
Pielikumi ir arī daudzdaļīga ziņojuma daļas. Jūs varat tos identificēt, izmantojot to Content-Disposition
galveni, un saglabāt to dekodēto pamattekstu.
from email.message import EmailMessage
from email import message_from_string
import os
# Piemērs e-pastam ar vienkāršu pielikumu
email_with_attachment = """
From: attach@example.com
To: user@example.com
Subject: Pievienots dokuments
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="_----------=_XYZ"
--_----------=_XYZ
Content-Type: text/plain; charset="utf-8"
Šeit ir jūsu pieprasītais dokuments.
--_----------=_XYZ
Content-Type: application/pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="document.pdf"
JVBERi0xLjQKMSAwIG9iagpbL1BERi9UZXh0L0ltYWdlQy9JbWFnZUkvSW1hZ0VCXQplbmRvYmoK
--_----------=_XYZ--
"""
msg = message_from_string(email_with_attachment)
output_dir = 'parsed_attachments'
os.makedirs(output_dir, exist_ok=True)
print("\n--- Pielikumu apstrāde ---")
for part in msg.iter_attachments():
filename = part.get_filename()
if filename:
filepath = os.path.join(output_dir, filename)
try:
with open(filepath, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f"Saglabāts pielikums: {filepath} (Tips: {part.get_content_type()})")
except Exception as e:
print(f"Kļūda saglabājot {filename}: {e}")
else:
print(f"Atrasts pielikums bez faila nosaukuma (Content-Type: {part.get_content_type()})")
# Iztīrīt izvades direktoriju
# import shutil
# shutil.rmtree(output_dir)
Paskaidrojums:
iter_attachments()
īpaši atgriež daļas, kas, visticamāk, ir pielikumi (t.i., tām irContent-Disposition: attachment
galvene vai tās nav citādi klasificētas).get_filename()
iegūst faila nosaukumu noContent-Disposition
galvenes.part.get_payload(decode=True)
iegūst pielikuma neapstrādātu bināro saturu, kas jau ir dekodēts nobase64
vaiquoted-printable
.
Kodējumu un rakstzīmju kopu dekodēšana
Pakotne email
lieliski automātiski dekodē kopīgos pārsūtīšanas kodējumus (piemēram, base64
, quoted-printable
), kad izsaucat get_payload(decode=True)
. Attiecībā uz pašu teksta saturu tā mēģina izmantot rakstzīmju kopu charset
, kas norādīta Content-Type
galvenē. Ja rakstzīmju kopa nav norādīta vai tā ir nederīga, jums, iespējams, būs jāapstrādā tā graciozi.
from email.message import EmailMessage
from email import message_from_string
# Piemērs ar potenciāli problemātisku rakstzīmju kopu
email_latin1 = """
From: legacy@example.com
To: new_system@example.com
Subject: Speciālās rakstzīmes: àéíóú
Content-Type: text/plain; charset="iso-8859-1"
This message contains Latin-1 characters: àéíóú
"""
msg = message_from_string(email_latin1)
if msg.is_multipart():
for part in msg.iter_parts():
payload = part.get_payload(decode=True)
charset = part.get_content_charset() or 'utf-8'
try:
print(f"Dekodēts (Rakstzīmju kopa: {charset}): {payload.decode(charset)}")
except UnicodeDecodeError:
print(f"Neizdevās dekodēt ar {charset}. Mēģinu alternatīvu...")
# Atgriezeniskā iespēja uz kopīgu rakstzīmju kopu vai 'latin-1', ja to gaida
print(f"Dekodēts (Alternatīva Latin-1): {payload.decode('latin-1', errors='replace')}")
else:
payload = msg.get_payload(decode=True)
charset = msg.get_content_charset() or 'utf-8'
try:
decoded_content = payload.decode(charset)
print(f"Dekodēts (Rakstzīmju kopa: {charset}): {payload.decode(charset)}")
except UnicodeDecodeError:
print(f"Neizdevās dekodēt ar {charset}. Mēģinu alternatīvu...")
print(f"Dekodēts (Alternatīva Latin-1): {payload.decode('latin-1', errors='replace')}")
Paskaidrojums:
- Vienmēr mēģiniet izmantot rakstzīmju kopu, kas norādīta
Content-Type
galvenē. - Izmantojiet
try-except UnicodeDecodeError
bloku, lai nodrošinātu noturību, īpaši strādājot ar e-pastiem no dažādiem un potenciāli nestandarta avotiem. errors='replace'
vaierrors='ignore'
var izmantot ar.decode()
, lai apstrādātu rakstzīmes, kuras nevar kartēt uz mērķa kodējumu, tādējādi novēršot kļūmes.
Papildu parsēšanas scenāriji
Reāli e-pasti var būt ļoti sarežģīti, ar ligzdotām daudzdaļīgām struktūrām. Pakotnes email
rekursīvais raksturs padara to navigāciju vienkāršu. Jūs varat apvienot is_multipart()
ar iter_parts()
, lai pārvietotos cauri dziļi ligzdotiem ziņojumiem.
from email.message import EmailMessage
from email import message_from_string
def parse_email_part(part, indent=0):
prefix = " " * indent
content_type = part.get_content_type()
charset = part.get_content_charset() or 'N/A'
print(f"{prefix}Daļas tips: {content_type}, Rakstzīmju kopa: {charset}")
if part.is_multipart():
for subpart in part.iter_parts():
parse_email_part(subpart, indent + 1)
elif part.get_filename(): # Tas ir pielikums
print(f"{prefix} Pielikums: {part.get_filename()} (Izmērs: {len(part.get_payload(decode=True))} baiti)")
else: # Tā ir parasta teksta/html pamatteksta daļa
payload = part.get_payload(decode=True)
try:
decoded_content = payload.decode(charset)
# print(f"{prefix} Saturs (pirmās 100 rakstzīmes): {decoded_content[:100]}...") # Īsuma dēļ
except UnicodeDecodeError:
print(f"{prefix} Saturs: (Binārais vai neatkodējamais teksts)")
complex_email_raw = """
From: complex@example.com
To: receiver@example.com
Subject: Sarežģīts e-pasts ar HTML, vienkāršu tekstu un pielikumu
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="outer_boundary"
--outer_boundary
Content-Type: multipart/alternative; boundary="inner_boundary"
--inner_boundary
Content-Type: text/plain; charset="utf-8"
Vienkāršs teksta saturs.
--inner_boundary
Content-Type: text/html; charset="utf-8"
<html><body><h2>HTML Saturs</h2></body></html>
--inner_boundary--
--outer_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="data.bin"
SGVsbG8gV29ybGQh
--outer_boundary--
"""
msg = message_from_string(complex_email_raw)
print("\n--- Sarežģītas e-pasta struktūras šķērsošana ---")
parse_email_part(msg)
Paskaidrojums:
- Rekursīvā funkcija
parse_email_part
demonstrē, kā pārvietoties pa visu ziņojuma koku, identificējot daudzdaļīgās daļas, pielikumus un pamatteksta saturu katrā līmenī. - Šis modelis ir ļoti elastīgs, lai iegūtu specifiskus satura tipus no dziļi ligzdotiem e-pastiem.
Izveide pret parsēšanu: salīdzinošā perspektīva
Lai gan tās ir atšķirīgas operācijas, izveide un parsēšana ir divas vienas monētas puses: MIME ziņojumu apstrāde. Izpratne par vienu neizbēgami palīdz izprast otru.
Izveide (sūtīšana):
- Fokuss: Pareiza galveņu, satura un pielikumu salikšana standartam atbilstošā MIME struktūrā.
- Galvenais rīks:
email.message.EmailMessage
ar tādām metodēm kāset_content()
,add_attachment()
,add_alternative()
,add_related()
. - Galvenās problēmas: Nodrošināt pareizus MIME tipus, rakstzīmju kopas (īpaši UTF-8 globālajam atbalstam),
Content-Transfer-Encoding
un pareizu galveņu formatēšanu. Kļūdas var izraisīt to, ka e-pasti netiek pareizi attēloti, pielikumi tiek sabojāti vai ziņojumi tiek atzīmēti kā surogātpasts.
Parsēšana (saņemšana):
- Fokuss: Neapstrādāta e-pasta baitu plūsmas sadalīšana sastāvdaļās, iegūstot specifiskas galvenes, pamatteksta saturu un pielikumus.
- Galvenais rīks:
email.parser.BytesParser
vaiemail.message_from_bytes()
, pēc tam navigējot pa iegūtoEmailMessage
objektu ar tādām metodēm kāis_multipart()
,iter_parts()
,get_payload()
,get_filename()
un piekļuvi galvenēm. - Galvenās problēmas: Bojātu e-pastu apstrāde, rakstzīmju kodējumu pareiza identificēšana (īpaši, ja tie ir neskaidri), trūkstošo galveņu apstrāde un datu noturīga iegūšana no dažādām MIME struktūrām.
Ziņojumam, ko veidojat, izmantojot EmailMessage
, jābūt pilnībā parsējamam ar BytesParser
. Līdzīgi, izpratne par parsēšanas laikā iegūto MIME struktūru sniedz jums ieskatu, kā pašiem veidot sarežģītus ziņojumus.
Labākās prakses globālai e-pasta apstrādei ar Python
Lietojumprogrammām, kas mijiedarbojas ar globālu auditoriju vai apstrādā dažādus e-pasta avotus, apsveriet šādas labākās prakses:
- Standartizēt uz UTF-8: Vienmēr izmantojiet UTF-8 visam teksta saturam, gan veidojot, gan gaidot to parsēšanas laikā. Tas ir globālais standarts rakstzīmju kodēšanai un novērš bojātu tekstu.
- Validēt e-pasta adreses: Pirms sūtīšanas validējiet saņēmēju e-pasta adreses, lai nodrošinātu piegādi. Parsēšanas laikā esiet gatavi potenciāli nederīgām vai nepareizi formatētām adresēm galvenēs `From`, `To` vai `Cc`.
- Rūpīga testēšana: Testējiet savu e-pasta izveidi ar dažādiem e-pasta klientiem (Gmail, Outlook, Apple Mail, Thunderbird) un platformām, lai nodrošinātu konsekventu HTML un pielikumu atveidošanu. Parsēšanai testējiet ar plašu paraugu e-pastu klāstu, ieskaitot tos, kuriem ir neparasti kodējumi, trūkstošas galvenes vai sarežģītas ligzdotas struktūras.
- Sanitizēt parsēto ievadi: Vienmēr uzskatiet no ienākošajiem e-pastiem iegūto saturu par neuzticamu. Sanitizējiet HTML saturu, lai novērstu XSS uzbrukumus, ja to rādāt tīmekļa lietojumprogrammā. Validējiet pielikumu failu nosaukumus un tipus, lai novērstu ceļa pārvietošanas vai citas drošības ievainojamības, saglabājot failus.
- Noturīga kļūdu apstrāde: Īstenojiet visaptverošus
try-except
blokus, dekodējot pamattekstus vai piekļūstot potenciāli trūkstošām galvenēm. Graciozi apstrādājietUnicodeDecodeError
vaiKeyError
. - Apstrādāt lielus pielikumus: Ņemiet vērā pielikumu izmērus, gan veidojot (lai nepārsniegtu pasta servera ierobežojumus), gan parsējot (lai novērstu pārmērīgu atmiņas lietošanu vai diska vietas patēriņu). Apsveriet lielu pielikumu straumēšanu, ja to atbalsta jūsu sistēma.
- Izmantojiet
email.policy
: Kritiskām lietojumprogrammām skaidri izvēlietiesemail.policy
(piemēram,policy.SMTP
), lai nodrošinātu stingru atbilstību e-pasta standartiem, kas var ietekmēt piegādi un savietojamību. - Metadatu saglabāšana: Parsēšanas laikā izlemiet, kādi metadati (galvenes, sākotnējās robežvirknes) ir svarīgi saglabāšanai, īpaši, ja veidojat pasta arhīva vai pārsūtīšanas sistēmu.
Secinājums
Python email
pakotne ir neticami jaudīga un elastīga bibliotēka ikvienam, kam nepieciešams programmatiski mijiedarboties ar e-pastu. Apgūstot gan MIME ziņojumu izveidi, gan noturīgu ienākošo e-pastu parsēšanu, jūs iegūstat spēju izveidot sarežģītas e-pasta automatizācijas sistēmas, veidot e-pasta klientus, analizēt e-pasta datus un integrēt e-pasta funkcionalitāti praktiski jebkurā lietojumprogrammā.
Pakotne pārdomāti apstrādā MIME pamatā esošās sarežģītības, ļaujot izstrādātājiem koncentrēties uz savas e-pasta mijiedarbības saturu un loģiku. Neatkarīgi no tā, vai sūtāt personalizētus biļetenus globālai auditorijai vai iegūstat kritiskus datus no automatizētiem sistēmas ziņojumiem, dziļa izpratne par email
pakotni izrādīsies nenovērtējama, veidojot uzticamus, savietojamus un globāli apzinīgus e-pasta risinājumus.