Comment utiliser les modules email, smtplib, poplib, imaplib pour envoyer et recevoir des e-mails en Python

PHPz
Libérer: 2023-05-16 23:44:26
avant
1719 Les gens l'ont consulté

Le parcours d'un e-mail est le suivant :

  • Mail User Agent (MUA) fait référence à un client de messagerie ou à un logiciel utilisé par un utilisateur pour accéder à son compte de messagerie. (c'est-à-dire un logiciel de messagerie similaire à Outlook)

  • MTA : Mail Transfer Agent - L'agent de transfert de courrier correspond aux fournisseurs de services de messagerie, tels que NetEase, Sina, etc.

  • MDA : Agent de livraison du courrier——Agent de livraison du courrier. Un serveur du fournisseur de services de messagerie

Expéditeur-> MUA -> MTA -> Plusieurs MTA ->- MUA <- Destinataires

souhaitent que les programmes d'écriture soient envoyés et reçus. les e-mails consistent essentiellement à :

  • Écrire MUA pour envoyer des e-mails à MTA ;

  • Écrire MUA pour recevoir des e-mails de MDA ;

Lors de l'envoi d'e-mails, le protocole utilisé par MUA et MTA est SMTP : Simple Mail Transfer Protocol. Le protocole SMTP est également utilisé du MTA suivant vers un autre MTA.

Lors de la réception des e-mails, MUA et MDA utilisent deux protocoles : POP : Post Office Protocol, la version actuelle est la 3, communément appelée POP3 ; IMAP : Internet Message Access Protocol, la version actuelle est la 4, l'avantage est qu'il ne peut pas récupérer uniquement les e-mails, mais aussi manipuler directement les e-mails stockés sur MDA, comme les déplacer de la boîte de réception vers la corbeille, etc.

1. SMTP (Simple Mail Transfer Protocol)

est le Simple Mail Transfer Protocol. Il s'agit d'un ensemble de règles pour transmettre les e-mails de l'adresse source à l'adresse de destination, qui contrôle la méthode de transfert des lettres.

smtplib de Python fournit un moyen très pratique d'envoyer des e-mails. Il encapsule simplement le protocole SMTP.

Python prend en charge SMTP avec deux modules : smtplib et email est responsable de la construction des e-mails, et smtplib. est responsable de l'envoi du courrier. smtplibemail两个模块,email负责构造邮件,smtplib负责发送邮件。

1、构造邮件:email.mime类型

构造一个邮件对象就是一个Messag对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下:

Message
+- MIMEBase
   +- MIMEMultipart
   +- MIMENonMultipart
      +- MIMEMessage
      +- MIMEText
      +- MIMEImage
Copier après la connexion

首先,我们来构造一个最简单的纯文本邮件,然后,通过SMTP发出去。

from email.mime.text import MIMEText
msg = MIMEText(&#39;hello, send by Python...&#39;, &#39;plain&#39;, &#39;utf-8&#39;)
Copier après la connexion

注意到构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入&#39;plain&#39;,最终的MIME就是&#39;text/plain&#39;,最后一定要用utf-8编码保证多语言兼容性。

2、创建 SMTP 对象

语法如下:

import smtplib
smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
Copier après la connexion

参数说明:

  • host: SMTP 服务器主机。这个参数可选,你可以根据需要指定主机的IP地址或者域名,例如:runoob.com。

  • port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下 SMTP 端口号为25。

  • local_hostname: 如果 SMTP 在你的本机上,你只需要指定服务器地址为 localhost 即可。

3、Python SMTP 对象使用 sendmail 方法发送邮件

语法如下:

SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
Copier après la connexion

参数说明:

  • from_addr: 邮件发送者地址。

  • to_addrs: 字符串列表,邮件发送地址。

  • msg: 发送消息

这里要注意一下第三个参数,msg 是字符串,表示邮件。要发送邮件,就必须注意信息的格式,因为邮件通常包括标题、发件人、收件人、邮件内容和附件等。这个格式就是 smtp 协议中定义的格式。

二、实例

2:本机已安装支持 SMTP 的服务

以下执行实例需要你本机已安装了支持 SMTP 的服务。

sendmail()方法就是发邮件,由于可以一次发给多个人,所以传入一个list,邮件正文是一个stras_string()MIMEText对象变成str

经过Header对象编码的文本,包含utf-8编码信息和Base64编码的文本。

以下是一个使用 Python 发送邮件简单的实例:

import smtplib
from email.mime.text import MIMEText
from email.header import Header
 
sender = &#39;from@runoob.com&#39;
receivers = [&#39;429240967@qq.com&#39;]  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
 
# 三个参数:第一个为文本内容,第二个 plain 设置文本格式,第三个 utf-8 设置编码
message = MIMEText(&#39;Python 邮件发送测试内容...&#39;, &#39;plain&#39;, &#39;utf-8&#39;)
message[&#39;From&#39;] = Header("菜鸟教程", &#39;utf-8&#39;)   # 发送者
message[&#39;To&#39;] =  Header("测试", &#39;utf-8&#39;)        # 接收者
message[&#39;Subject&#39;] = Header(&#39;Python SMTP 邮件测试主题&#39;, &#39;utf-8&#39;)
 
try:
    smtpObj = smtplib.SMTP(&#39;localhost&#39;)
    smtpObj.sendmail(sender, receivers, message.as_string())
    print "邮件发送成功"
except smtplib.SMTPException:
    print "Error: 无法发送邮件"
Copier après la connexion

2、使用第三方 SMTP 服务

如果我们本机没有 sendmail 访问,也可以使用其他邮件服务商的 SMTP 访问(QQ、网易、Google等)。

login()方法用来登录SMTP服务器

发收件件人的名字没有显示为友好的名字,比如Mr Green

使用 formataddr方法来格式化一个邮件地址。如果包含中文,需要通过Header对象进行编码。

msg[&#39;To&#39;]接收的是字符串而不是list,如果有多个邮件地址,用,

1. Construire un email : type email.mime

Construire un objet email est un objet Message Si vous construisez un objet MIMEText, cela signifie. un objet de courrier texte. Si vous construisez un objet MIMEImage, il représente une image sous forme de pièce jointe. Pour combiner plusieurs objets, utilisez l'objet MIMEMultipart et MIMEBase <. /code>peut représenter n’importe quel objet. Leur relation d'héritage est la suivante : 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">import smtplib from email.mime.text import MIMEText from email.utils import formataddr # 第三方 SMTP 服务 mail_host = &quot;mail.sss.com&quot; # 设置服务器 mail_user = &quot;it_system@sss.com&quot; # 用户名 mail_pass = &quot;Ssss201709#&quot; # 口令 sender = &amp;#39;it_system@tcl.com&amp;#39; receivers = &amp;#39;sss.yang@tcsssl.com&amp;#39; # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 message = MIMEText(&amp;#39;Python 邮件内容测试...&amp;#39;, &amp;#39;plain&amp;#39;, &amp;#39;utf-8&amp;#39;) message[&amp;#39;From&amp;#39;] = formataddr((&amp;#39;SCBC-啊iT&amp;#39;, sender)) message[&amp;#39;To&amp;#39;] = formataddr((&amp;#39;杨生&amp;#39;, receivers)) message[&amp;#39;Subject&amp;#39;] = &amp;#39;Python SMTP 邮件测试&amp;#39; try: smtpObj = smtplib.SMTP() smtpObj.connect(mail_host, 25) # 25 为 SMTP 端口号 smtpObj.login(mail_user, mail_pass) smtpObj.sendmail(sender, receivers, message.as_string()) print(&quot;邮件发送成功&quot;) except smtplib.SMTPException: print(&quot;Error: 无法发送邮件&quot;)</pre><div class="contentsignin">Copier après la connexion</div></div><div class="contentsignin">Copier après la connexion</div></div>🎜Tout d'abord, nous construisons l'e-mail en texte brut le plus simple, puis l'envoyons via SMTP. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">mail_msg = &quot;&quot;&quot; Python 邮件内容测试... 这是一个链接 &quot;&quot;&quot; message = MIMEText(mail_msg, &amp;#39;html&amp;#39;, &amp;#39;utf-8&amp;#39;)</pre><div class="contentsignin">Copier après la connexion</div></div><div class="contentsignin">Copier après la connexion</div></div>🎜 a remarqué que lors de la construction de l'objet <code>MIMEText, le premier paramètre est le corps de l'e-mail et le deuxième paramètre est le sous-type de MIME dans 'plain' et le. final MIME Il s'agit de 'text/plain' Enfin, vous devez utiliser l'encodage utf-8 pour garantir la compatibilité multilingue. 🎜

2. Créer un objet SMTP

🎜La syntaxe est la suivante : 🎜
from email.mime.multipart import MIMEMultipart

# 创建一个带附件的实例
message = MIMEMultipart()

message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;, sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;

mail_msg = """
Python 邮件内容测试...


这是一个链接


"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;))

# 构造附件1,传送当前目录下的 test.txt 文件
att = MIMEText(open(&#39;32.txt&#39;, &#39;rb&#39;).read(), &#39;base64&#39;, &#39;utf-8&#39;)
att["Content-Type"] = &#39;application/octet-stream&#39;
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att["Content-Disposition"] = &#39;attachment; filename="32.txt"&#39;
message.attach(att)
Copier après la connexion
Copier après la connexion
🎜Description du paramètre : 🎜🎜🎜🎜host : hôte du serveur SMTP. Ce paramètre est facultatif. Vous pouvez spécifier l'adresse IP ou le nom de domaine de l'hôte selon vos besoins, par exemple : runoob.com. 🎜🎜🎜🎜port : Si vous fournissez le paramètre host, vous devez spécifier le numéro de port utilisé par le service SMTP. Généralement, le numéro de port SMTP est 25. 🎜🎜🎜🎜local_hostname : Si SMTP est sur votre ordinateur local, il vous suffit de spécifier l'adresse du serveur en tant que localhost. 🎜🎜🎜

3. L'objet Python SMTP utilise la méthode sendmail pour envoyer des emails

🎜La syntaxe est la suivante : 🎜
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage

# 创建一个带附件的实例
message = MIMEMultipart()

message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;, sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;

mail_msg = """
Python 邮件内容测试...


这是一个链接


图片演示:





"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;))

# 指定图片为当前目录
with  open(&#39;a.jpg&#39;, &#39;rb&#39;) as fp:
    msgImage = MIMEImage(fp.read())

# 定义图片 ID,在 HTML 文本中引用
msgImage.add_header(&#39;Content-ID&#39;, &#39;&#39;)
message.attach(msgImage)
Copier après la connexion
Copier après la connexion
🎜Description du paramètre : 🎜🎜🎜🎜from_addr : Adresse de l'expéditeur de l'e-mail. 🎜🎜🎜🎜to_addrs : liste de chaînes, adresse d'envoi email. 🎜🎜🎜🎜msg : Envoyer un message 🎜🎜🎜🎜 Veuillez noter le troisième paramètre ici, msg est une chaîne, représentant un e-mail. Pour envoyer un email, vous devez faire attention au format des informations, car l'e-mail comprend généralement un titre, un expéditeur, un destinataire, le contenu de l'e-mail, des pièces jointes, etc. Ce format est le format défini dans le protocole smtp. 🎜🎜2. Exemple🎜

2 : Un service prenant en charge SMTP a été installé sur cette machine

🎜Les exemples d'exécution suivants nécessitent qu'un service prenant en charge SMTP soit installé sur votre machine. 🎜🎜La méthode sendmail() consiste à envoyer un e-mail Comme il peut être envoyé à plusieurs personnes à la fois, une list est transmise et le corps de l'e-mail est transmis. a str , as_string() transforme l'objet MIMEText en str. 🎜🎜Texte encodé par l'objet Header, y compris les informations d'encodage UTF-8 et le texte encodé Base64. 🎜🎜Ce qui suit est un exemple simple d'utilisation de Python pour envoyer des e-mails : 🎜
# 指定图片为当前目录
with  open(&#39;a.jpg&#39;, &#39;rb&#39;) as fp:
    # 设置附件的MIME和文件名,这里是png类型:
    mime = MIMEBase(&#39;image&#39;, &#39;jpg&#39;, filename=&#39;a.jpg&#39;)
    # 加上必要的头信息:
    mime.add_header(&#39;Content-Disposition&#39;, &#39;attachment&#39;, filename=&#39;附件显示名称.jpg&#39;)
    mime.add_header(&#39;Content-ID&#39;, &#39;&#39;)  # 如果有多个文件需要使用.format(index)
    mime.add_header(&#39;X-Attachment-Id&#39;, &#39;0&#39;)  # 如果有多个文件需要使用.format(index)
    # 把附件的内容读进来:
    mime.set_payload(fp.read())
    # 用Base64编码:
    encoders.encode_base64(mime)
    # 添加到MIMEMultipart:
    message.attach(mime)
Copier après la connexion
Copier après la connexion

2. Utilisez un service SMTP tiers

🎜Si nous n'avons pas d'accès sendmail localement, nous pouvons également utiliser l'accès SMTP depuis d'autres fournisseurs de services de messagerie (QQ, NetEase, Google, etc.). 🎜🎜La méthode login() est utilisée pour se connecter au serveur SMTP 🎜🎜Le nom du destinataire n'est pas affiché comme un nom convivial, tel que M. Green 🎜🎜Utilisez ; la méthode formataddr pour formater une adresse email. S'il contient du chinois, il doit être codé via l'objet Header. 🎜🎜msg['To'] reçoit une chaîne au lieu d'une liste. S'il y a plusieurs adresses e-mail, utilisez simplement , pour les séparer. 🎜
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# 第三方 SMTP 服务
mail_host = "mail.sss.com"  # 设置服务器
mail_user = "it_system@sss.com"  # 用户名
mail_pass = "Ssss201709#"  # 口令

sender = &#39;it_system@tcl.com&#39;
receivers = &#39;sss.yang@tcsssl.com&#39;  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱

message = MIMEText(&#39;Python 邮件内容测试...&#39;, &#39;plain&#39;, &#39;utf-8&#39;)
message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;,   sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;

try:
    smtpObj = smtplib.SMTP()
    smtpObj.connect(mail_host, 25)  # 25 为 SMTP 端口号
    smtpObj.login(mail_user, mail_pass)
    smtpObj.sendmail(sender, receivers, message.as_string())
    print("邮件发送成功")
except smtplib.SMTPException:
    print("Error: 无法发送邮件")
Copier après la connexion
Copier après la connexion

3、使用Python发送HTML格式的邮件

Python在构造MIMEText对象时,把HTML字符串传进去,再把第二个参数由plain变为html就可以了:

具体代码如下:

mail_msg = """
Python 邮件内容测试...


这是一个链接


"""
message = MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;)
Copier après la connexion
Copier après la connexion

4、Python 发送带附件的邮件

带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart对象代表邮件本身,然后往里面加上一个MIMEText作为邮件正文,再继续往里面加上表示附件的MIMEBase对象即可。

发送带附件的邮件,首先要创建MIMEMultipart()实例,然后构造附件,如果有多个附件,可依次构造,最后利用smtplib.smtp发送。

from email.mime.multipart import MIMEMultipart

# 创建一个带附件的实例
message = MIMEMultipart()

message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;, sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;

mail_msg = """
Python 邮件内容测试...


这是一个链接


"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;))

# 构造附件1,传送当前目录下的 test.txt 文件
att = MIMEText(open(&#39;32.txt&#39;, &#39;rb&#39;).read(), &#39;base64&#39;, &#39;utf-8&#39;)
att["Content-Type"] = &#39;application/octet-stream&#39;
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att["Content-Disposition"] = &#39;attachment; filename="32.txt"&#39;
message.attach(att)
Copier après la connexion
Copier après la connexion

5、在 HTML 文本中添加图片

要把图片嵌入到邮件正文中,我们只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x即可。

邮件的 HTML 文本中一般邮件服务商添加外链是无效的,正确添加图片的实例如下所示:

from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage

# 创建一个带附件的实例
message = MIMEMultipart()

message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;, sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;

mail_msg = """
Python 邮件内容测试...


这是一个链接


图片演示:





"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;))

# 指定图片为当前目录
with  open(&#39;a.jpg&#39;, &#39;rb&#39;) as fp:
    msgImage = MIMEImage(fp.read())

# 定义图片 ID,在 HTML 文本中引用
msgImage.add_header(&#39;Content-ID&#39;, &#39;&#39;)
message.attach(msgImage)
Copier après la connexion
Copier après la connexion

或者通过MIMEBase来添加图片

# 指定图片为当前目录
with  open(&#39;a.jpg&#39;, &#39;rb&#39;) as fp:
    # 设置附件的MIME和文件名,这里是png类型:
    mime = MIMEBase(&#39;image&#39;, &#39;jpg&#39;, filename=&#39;a.jpg&#39;)
    # 加上必要的头信息:
    mime.add_header(&#39;Content-Disposition&#39;, &#39;attachment&#39;, filename=&#39;附件显示名称.jpg&#39;)
    mime.add_header(&#39;Content-ID&#39;, &#39;&#39;)  # 如果有多个文件需要使用.format(index)
    mime.add_header(&#39;X-Attachment-Id&#39;, &#39;0&#39;)  # 如果有多个文件需要使用.format(index)
    # 把附件的内容读进来:
    mime.set_payload(fp.read())
    # 用Base64编码:
    encoders.encode_base64(mime)
    # 添加到MIMEMultipart:
    message.attach(mime)
Copier après la connexion
Copier après la connexion

6、同时支持HTML和Plain格式

如果我们发送HTML邮件,收件人通过浏览器或者Outlook之类的软件是可以正常浏览邮件内容的,但是,如果收件人使用的设备太古老,查看不了HTML邮件怎么办?

办法是在发送HTML的同时再附加一个纯文本,如果收件人无法查看HTML格式的邮件,就可以自动降级查看纯文本邮件。

利用MIMEMultipart就可以组合一个HTML和Plain,要注意指定subtype是alternative

msg = MIMEMultipart(&#39;alternative&#39;)
msg[&#39;From&#39;] = ...
msg[&#39;To&#39;] = ...
msg[&#39;Subject&#39;] = ...

msg.attach(MIMEText(&#39;hello&#39;, &#39;plain&#39;, &#39;utf-8&#39;))
msg.attach(MIMEText(&#39;Hello&#39;, &#39;html&#39;, &#39;utf-8&#39;))
# 正常发送msg对象...
Copier après la connexion

7、加密SMTP

如果使用标准的25端口连接SMTP服务器发送邮件,即使身份验证成功,因为明文传输的缘故,整个邮件发送过程都有可能被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件。

在某些邮件服务提供商(例如Gmail)中,SMTP服务必须使用加密传输。我们来看看如何通过Gmail提供的安全SMTP发送邮件。

只需要在创建SMTP对象后,立刻调用starttls()方法,就创建了安全连接。后面的代码和前面的发送邮件代码完全一样。

必须知道,Gmail的SMTP端口是587,因此,修改代码如下:

smtp_server = &#39;smtp.gmail.com&#39;
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代码和前面的一模一样:
server.set_debuglevel(1)
Copier après la connexion

三、使用poplib接收邮件

收取邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上。收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3

Python内置一个poplib模块,实现了POP3协议,可以直接用来收邮件。

POP3 的命令和响应数据都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作为行结束符,响应数据包括一个表示返回状态的符号(+/)和描述信息。

请求和响应的标准格式如下:

请求标准格式:命令 [参数] CRLF
响应标准格式:+OK /[-ERR] description CRLF

POP3 协议客户端的命令和服务器端对应的响应数据如下:

  • user name:向 POP 服务器发送登录的用户名。

  • pass string:向 POP 服务器发送登录的密码。

  • quit:退出 POP 服务器。

  • stat:统计邮件服务器状态,包括邮件数和总大小。

  • list [msg_no]:列出全部邮件或指定邮件。返回邮件编号和对应大小。

  • retr msg_no:获取指定邮件的内容(根据邮件编号来获取,编号从 1 开始)。

  • dele msg_no:删除指定邮件(根据邮件编号来删除,编号从 1 开始)。

  • noop:空操作。仅用于与服务器保持连接。

  • rset:用于撤销 dele 命令。

poplib 模块完全模拟了上面命令,poplib.POP3 或 poplib.POP3_SSL 为上面命令提供了相应的方法,开发者只要依次使用上面命令即可从服务器端下载对应的邮件

注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。

要把POP3收取的文本变成可以阅读的邮件,还需要用email模块提供的各种类来解析原始文本,变成可阅读的邮件对象。

所以,收取邮件分两步:

第一步:使用poplib.POP3 或 poplib.POP3_SSL 按 POP3 协议把邮件的原始文本下载到本地;

用POP3获取邮件其实很简单,要获取所有邮件,只需要循环使用retr()把每一封邮件内容拿到即可。真正麻烦的是把邮件的原始内容解析为可以阅读的邮件对象。

import poplib
from email.parser import Parser
# email.parser 解析电子邮件,返回这个对象的email.message.Message实例
from email.header import decode_header
from email.utils import parseaddr

# 服务器及用户信息
host = &#39;mail.tcl.com&#39;
username = &#39;bobin.yang@tcl.com&#39;
password = &#39;Ybb7654321&#39;

# 连接到POP3服务器
conn = poplib.POP3_SSL(host)
# 注意qq邮箱使用SSL连接
# 设置调试模式,可以看到与服务器的交互信息
conn.set_debuglevel(1)

# 打印POP3服务器的欢迎文字
print(conn.getwelcome().decode("utf-8"))

# 身份认证
conn.user(username)
conn.pass_(password)

# 获取服务器上信件信息,返回一个列表,第一项是一共有多少封邮件,第二项是共有多少字节
# stat()返回邮件数量和占用空间
mail_total, total_size = conn.stat()
print(&#39;message: %s.Size:%s&#39; % (mail_total, total_size))

# list()返回(response, [&#39;mesg_num octets&#39;, ...], octets),第二项是编号
resp, mails, octets = conn.list()
print(mails)
# 返回的列表类似[b&#39;1 82923&#39;, b&#39;2 2184&#39;, ...]

# 获取最新一封邮件,注意索引号从1开始
# POP3.retr(which) 检索序号which的这个邮件,然后设置他的出现标志 返回(response, [&#39;line&#39;, ...], octets)这个三元组
resp, lines, ocetes = conn.retr(len(mails))
print(&#39;lines:&#39;, len(lines))
# lines 存储了邮件的原始文本的每一行
# 可以获得整个邮件的原始文本
print("-------------------")
Copier après la connexion

第二步:使用 email.parser.Parser或BytesParser 解析邮件内容为消息对象,然后,用适当的形式把邮件内容展示给用户即可。

解析邮件的过程和上一节构造邮件正好相反。

程序在创建 BytesParser(解析字节串格式的邮件数据)或 Parser(解析字符串格式的邮件数据)时,必须指定 policy=default;否则,BytesParse 或 Parser 解析邮件数据得到的就是过时的 Message 对象,,不是新的 EmailMessage,处理起来非常不方便。

1、使用 email.parser.Parser解析邮件内容为 email.message.Message(过时,不推荐)
msg = b&#39;\r\n&#39;.join(lines).decode(&#39;utf-8&#39;)
# 解析出邮件
msg = Parser().parsestr(msg)


# email.Parser.parsestr(text, headersonly=False)
# 与parser()方法类似,不同的是他接受一个字符串对象而不是一个类似文件的对象
# 可选的headersonly表示是否在解析玩标题后停止解析,默认为否
# 返回根消息对象

# 编码处理,文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示
def guess_charset(msg):
    charset = msg.get_charset()  # 从msg对象获取编码
    if charset is None:
        content_type = msg.get(&#39;Content-Type&#39;, &#39;&#39;).lower()  # 如果获取不到,再从content—type字段获取
        if &#39;charset&#39; in content_type:
            charset = content_type.split(&#39;charset=&#39;)[1].strip()
            return charset
    return charset


# 数据解码,邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode
def decode_str(s):
    value, charset = decode_header(s)[0]  # 数据,数据编码方式,from email.header import decode_header
    # decode_header()返回一个list,因为像Cc、Bcc这样的字段可能包含多个邮件地址,所以解析出来的会有多个元素。上面的代码我们偷了个懒,只取了第一个元素。
    if charset:
        value = value.decode(charset)
    return value


# print_ingo函数:解析邮件与构造邮件的步骤正好相反
def print_info(msg, indent=0):  # indent用于缩进显示
    if indent == 0:
        for header in [&#39;From&#39;, &#39;To&#39;, &#39;Subject&#39;]:  # 邮件的from、to、subject存在于根对象上
            value = msg.get(header, &#39;&#39;)
            if value:
                if header == &#39;Subject&#39;:
                    value = decode_str(value)  # 需要解码subject字符串
                else:
                    # 解码mail地址
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = &#39;%s&#39; % addr
            print(&#39;%s:  %s  %s&#39; % (header, value, name))
            print(&#39;-*-&#39; * 20)
    if msg.is_multipart():
        # 如果邮件对象是一个is_multipart,get_payload()返回一个list,包含所有子对象
        parts = msg.get_payload()  # 循环获得列表项
        for n, part in enumerate(parts):
            # print(&#39;%spart %s&#39; % (&#39;  &#39; * indent, n))
            # print(&#39;%s------------&#39; % (&#39;  &#39; * indent))
            # 递归打印没一个子对象
            print_info(part, indent + 1)
    else:
        # 邮件对象不是一个is_multipart,就根据content_type判断
        content_type = msg.get_content_type()  # 数据类型
        if content_type == &#39;text/plain&#39; or content_type == &#39;text/html&#39;:  # 纯文本 html文本
            # 纯文本或html内容
            content = msg.get_payload(decode=True)  # 获得文本对象的字符串而非对象本身
            charset = guess_charset(msg)  # 要检测文本编码
            if charset: content = content.decode(charset)
            content = &#39;%s&#39; % (content)
            print(content)  # 获取邮件文本内容,如果只有文本,打印显示的结果和邮件中看的效果一模一样
        else:
            print(content_type+&#39;不是文本&#39;)


print_info(msg, 0)

# 退出
conn.quit()
Copier après la connexion
2、使用email.parser.BytesParser 解析成email.message.EmailMessage对象

如果程序要获取邮件的发件人、收件人和主题,直接通过 EmailMessage 的相应属性来获取即可,与前面为 EmailMessage 设置发件人、收件人和主题的方式是对应的。
如果程序要读取 EmailMessage 的各部分,则需要调用该对象的 walk() 方法,该方法返回一个可迭代对象,程序使用 for 循环遍历 walk() 方法的返回值,对邮件内容进行逐项处理:

  • 如果邮件某项的 maintype 是 'multipart',则说明这一项是容器,用于包含邮件内容、附件等其他项。

  • 如果邮件某项的 maintype 是 'text',则说明这一项的内容是文本,通常就是邮件正文或文本附件。对于这种文本内容,程序直接将其输出到控制台中。

  • 如果邮件中某个项的 maintype 属性是“其他”,那么这一项的内容就是作为附件的,程序会将附件内容保存到本地文件中。

import os
import poplib
import mimetypes
from email.parser import Parser, BytesParser
from email.policy import default

msg_data = b&#39;\r\n&#39;.join(lines)
# 将字符串内容解析成邮件,此处一定要指定policy=default
msg = BytesParser(policy=default).parsebytes(msg_data)
print(type(msg))

print(&#39;发件人:&#39; + msg[&#39;from&#39;])
print(&#39;收件人:&#39; + msg[&#39;to&#39;])
print(&#39;主题:&#39; + msg[&#39;subject&#39;])
print(&#39;第一个收件人名字:&#39; + msg[&#39;to&#39;].addresses[0].username)
print(&#39;第一个发件人名字:&#39; + msg[&#39;from&#39;].addresses[0].username)
for part in msg.walk():
    counter = 1
    # 如果maintype是multipart,说明是容器(用于包含正文、附件等)
    if part.get_content_maintype() == &#39;multipart&#39;:
        continue
    # 如果maintype是multipart,说明是邮件正文部分
    elif part.get_content_maintype() == &#39;text&#39;:
        print(part.get_content())
    # 处理附件
    else:
        # 获取附件的文件名
        filename = part.get_filename()
        # 如果没有文件名,程序要负责为附件生成文件名
        if not filename:
            # 根据附件的contnet_type来推测它的后缀名
            ext = mimetypes.guess_extension(part.get_content_type())
            # 如果推测不出后缀名
            if not ext:
                # 使用.bin作为后缀名
                ext = &#39;.bin&#39;
            # 程序为附件来生成文件名
            filename = &#39;part-%03d%s&#39; % (counter, ext)
        counter += 1
        # 将附件写入的本地文件
        with open(os.path.join(&#39;.&#39;, filename), &#39;wb&#39;) as fp:
            fp.write(part.get_payload(decode=True))
# 退出服务器,相当于发送POP 3的quit命令
conn.quit()
Copier après la connexion

四、利用imaplib读取邮件文本内容及附件内容

通过IMAP协议来管理邮箱用的,称作交互邮件访问协议。

! encoding:utf8
&#39;&#39;&#39;
环境:
    Win10 64位 Python 2.7.5
参考:
    http://www.pythonclub.org/python-network-application/email-format
    http://blog.sina.com.cn/s/blog_4deeda2501016eyf.html
&#39;&#39;&#39;


import imaplib
import email


def parseHeader(message):
    """ 解析邮件首部 """
    subject = message.get(&#39;subject&#39;)  
    h = email.Header.Header(subject)
    dh = email.Header.decode_header(h)
    subject = unicode(dh[0][0], dh[0][1]).encode(&#39;gb2312&#39;)
    # 主题
    print subject
    print &#39;
&#39;
    # 发件人
    print &#39;From:&#39;, email.utils.parseaddr(message.get(&#39;from&#39;))[1]
    print &#39;
&#39;
    # 收件人
    print &#39;To:&#39;, email.utils.parseaddr(message.get(&#39;to&#39;))[1]
    print &#39;
&#39;
    # 抄送人
    print &#39;Cc:&#39;,email.utils.parseaddr(message.get_all(&#39;cc&#39;))[1]



def parseBody(message):
    """ 解析邮件/信体 """
    # 循环信件中的每一个mime的数据块
    for part in message.walk():
        # 这里要判断是否是multipart,是的话,里面的数据是一个message 列表
        if not part.is_multipart():
            charset = part.get_charset()
            # print &#39;charset: &#39;, charset
            contenttype = part.get_content_type()
            # print &#39;content-type&#39;, contenttype
            name = part.get_param("name") #如果是附件,这里就会取出附件的文件名
            if name:
                # 有附件
                # 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名
                fh = email.Header.Header(name)
                fdh = email.Header.decode_header(fh)
                fname = dh[0][0]
                print &#39;附件名:&#39;, fname
                # attach_data = par.get_payload(decode=True) # 解码出附件数据,然后存储到文件中

                # try:
                #     f = open(fname, &#39;wb&#39;) #注意一定要用wb来打开文件,因为附件一般都是二进制文件
                # except:
                #     print &#39;附件名有非法字符,自动换一个&#39;
                #     f = open(&#39;aaaa&#39;, &#39;wb&#39;)
                # f.write(attach_data)
                # f.close()
            else:
                #不是附件,是文本内容
                print part.get_payload(decode=True) # 解码出文本内容,直接输出来就可以了。
                # pass
            # print &#39;+&#39;*60 # 用来区别各个部分的输出


def getMail(host, username, password, port=993):
    try:
        serv = imaplib.IMAP4_SSL(host, port)
    except Exception, e:
        serv = imaplib.IMAP4(host, port)

    serv.login(username, password)
    serv.select()
    # 搜索邮件内容
    typ, data = serv.search(None, &#39;(FROM "xx@xxx.com")&#39;)

    count = 1
    pcount = 1
    for num in data[0].split()[::-1]:
        typ, data = serv.fetch(num, &#39;(RFC822)&#39;)
        text = data[0][1]
        message = email.message_from_string(text)   # 转换为email.message对象
        parseHeader(message)
        print &#39;
&#39;
        parseBody(message)   
        pcount += 1
        if pcount > count:
            break

    serv.close()
    serv.logout()


if __name__ == &#39;__main__&#39;:
    host = "imap.mail_serv.com" # "pop.mail_serv.com"
    username = "Trevor@mail_serv.com"
    password = "your_password"
    getMail(host, username, password)
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal