电子邮件,简称电邮,是指一种由寄件人将数字信息发送给一个人或者多个人的信息交换方式。
电邮包括三个部分:消息的“信封”、邮件标头、邮件内容。
电邮的格式:用户名@主机名(域名)。电邮地址是表示在某部主机上的一个用户账号。
电邮的报文格式包括两部分:邮件头部(主要包括收件人和发件人的地址、发送日期、邮件主题等)和邮件体(正文)。
报文头部主要关键字:To、Subject、CC(抄送,即此邮件应同时发给其他所列出的收件人)、From、Data
电子邮箱(E-mail地址)的获取需要在邮件服务器上进行申请。通常用户在邮件服务器上申请一个账号后,邮件服务器会为这个账号分配一定的空间。
用户想要发送一封电邮,需要遵循一定的通信规则,SMTP协议就是来定义这种通信规则的。通常把处理用户SMTP请求(邮件发送请求)的服务器称为SMTP服务器(邮件发送服务器)。
用户想要接受一封电邮,也要遵从一定的通信格式,POP3协议就是用来定义这种通信格式的。通常把处理用户POP3请求(邮件接收请求)的服务器称为POP3服务器(邮件接收服务器)。
发送电子邮件
SMTP发送电邮(smtplib模块)
SMTP(简单邮件传送协议),是一组由源地址到目的地址传送邮件的规则,用来控制邮件的中转方式。
smtplib模块,用于实现SMTP协议,发送邮件。
email模块帮助构造邮件格式。
创建SMTP对象:smtpObj=smtplib.SMTP([host [,port [,local_hostname]]])
host:SMTP服务器主机,可选参数。可以指定主机的IP地址或者域名。
port:如果指定了host参数,就需要指定SMTP服务器使用的端口号。一般情况下SMTP服务器的端口号为25。
local_hostname:如果SMTP在本机上,只需要指定服务器地址为localhost即可。
SMTP对象使用sendmail方法发送邮件:SMTP.sendmail(from_addr,to_addrs,msg[,mail_options,rept_options])
from_addr:邮件发送者地址。
to_addrs:字符串列表,邮件发送地址。
msg:发送消息,一般使用字符串。
首先需要设置发送邮箱的SMTP授权。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
sender="1064800303@qq.com"#发送者邮箱用户名
password="XXXXXX"#(不是真的邮箱密码)SMTP授权码
receiver=["wangyifan9901@yeah.net",]#收件人地址,必须是列表类型
message=MIMEText("来自Python的邮件","plain","utf-8")#邮件正文
message["From"]=Header("WYF","utf-8")#发件人显示名字
message["To"]=Header("Wyf","utf-8")#收件人显示名字
message["Subject"]="SMTP发送邮件"#邮件标题
try:
smtp=smtplib.SMTP_SSL("smtp.qq.com",465)#使用QQ企业邮箱服务器发送
smtp.login(sender,password)#登录
smtp.sendmail(sender,receiver,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("ERROR!",e)
我是选择QQ发给网易。中间出了很多类似535、Connection unexpectedly closed之类的错误,感觉就是三个地方,可以自行尝试,从别人那里抄过来的解决方法不一定有效:
1.password密码要是SMTP授权码
2.这个函数SMTP_SSL也有可能是SMTP
3.服务器的选择,尽量选择发送方的服务器吧。端口号看起来465最保险。我的资料上显示发送方服务器是smtp.exmail.qq.com,但是在PyCharm会报错535。
邮箱 | 发件服务器 | 非SSL协议端口 | SSL协议端口 |
---|---|---|---|
163 | smtp.163.com | 25 | 465/587 |
smtp.qq.com | 25 | 465/587 |
在浪费我1块钱发短信费用后,留下了感动的泪水。
PS:但是这个好像不能直接回复。
发送HTML格式的电子邮件
纯文本格式邮件只能是显示文字,要发送更丰富的内容可以发送HTML格式的邮件。即在使用MIMEText函数构造邮件消息体时将第二个参数指定格式为"html"。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
sender="1064800303@qq.com"#发送者邮箱用户名
password="XXXXXX"#邮箱密码,SMTP授权码
receiver=["wangyifan9901@yeah.net",]#收件人地址,必须是列表类型
mail_msg="""
<p>使用Python发送邮件</p>
<br>
<p><a href="http://www.baidu.com">这是一个超链接</p>
"""
message=MIMEText(mail_msg,"html","utf-8")#邮件正文
message["From"]=Header("WYF","utf-8")#发件人显示名字
message["To"]=Header("Wyf","utf-8")#收件人显示名字
message["Subject"]="SMTP发送邮件"#邮件标题
try:
smtp=smtplib.SMTP_SSL("smtp.qq.com",465)#使用QQ企业邮箱服务器发送
smtp.login(sender,password)#登录
smtp.sendmail(sender,receiver,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("ERROR!",e)
就是不知道为什么这个超链接在收件箱能点开,发件箱点不开。
发送带附件的邮件
在构造邮件消息体的时候需要使用MIMEMultipart来构建复合类型的消息体,然后把文本和附件一个一个地加进去。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart
sender="1064800303@qq.com"#发送者邮箱用户名
password="XXXXXX"#邮箱密码,SMTP授权码
receiver=["wangyifan9901@yeah.net",]#收件人地址,必须是列表类型
message=MIMEMultipart()
message["From"]=Header("WYF","utf-8")#发件人显示名字
message["To"]=Header("Wyf","utf-8")#收件人显示名字
message["Subject"]="SMTP发送邮件"#邮件标题
mail_msg="""
<p>使用Python发送邮件</p>
<br>
<p><a href="http://www.baidu.com">这是一个超链接</p>
"""
message.attach(MIMEText(mail_msg,"html","utf-8"))
attached_file=MIMEText(open(__file__,encoding="utf-8").read(),"base64","utf-8")#添加附件
attached_file["Content-Disposition"]='attachment;filename="a.txt"'
message.attach(attached_file)
try:
smtp=smtplib.SMTP_SSL("smtp.qq.com",465)#使用QQ企业邮箱服务器发送
smtp.login(sender,password)#登录
smtp.sendmail(sender,receiver,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("ERROR!",e)
发送图片
把图片作为附件添加到邮件消息体中,然后在HTML格式的正文中使用src=cid:img1格式嵌入即可。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
sender="1064800303@qq.com"#发送者邮箱用户名
password="XXXXXX"#邮箱密码,SMTP授权码
receiver=["wangyifan9901@yeah.net",]#收件人地址,必须是列表类型
message=MIMEMultipart()
message["From"]=Header("WYF","utf-8")#发件人显示名字
message["To"]=Header("Wyf","utf-8")#收件人显示名字
message["Subject"]="SMTP发送邮件"#邮件标题
msg_content=MIMEMultipart("alternative")
mail_msg="""
<p>使用Python发送带图片邮件</p>
<br>
<p>
图片
<img src="cid:img1'>
</p>
"""
msg_content.attach(MIMEText(mail_msg,"html","utf-8"))
message.attach(msg_content)
with open("1.jpg","rb")as f:
img1=MIMEImage(f.read())
img1.add_header("Content-ID","img1")#定义资源的名字为img1
message.attach(img1)
try:
smtp=smtplib.SMTP_SSL("smtp.qq.com",465)#使用QQ企业邮箱服务器发送
smtp.login(sender,password)#登录
smtp.sendmail(sender,receiver,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("ERROR!",e)
接收电子邮件
接收邮件的两种常用协议:
POP3协议(邮局协议版本3),允许电邮客户端下载服务器上的邮件,但是在客户端的操作不会反馈到服务器上。
IMAP协议(Internet邮件访问协议),提供Webmail与电邮客户端之间的双向通信,任何在客户端做的改变都会同步到服务器上。
使用POP3协议下载邮件(poplib模块)
import poplib
from email.parser import Parser
username="1064800303@qq.com"#登录邮箱用户名
password="XXXXXX"#邮箱密码,SMTP授权码
pop_server=poplib.POP3_SSL("pop.qq.com",995)#连接邮箱服务器
print(pop_server.getwelcome().decode("utf-8"))#打印出邮箱服务器的欢迎文字
pop_server.user(username)#登录邮箱服务器
pop_server.pass_(password)
print("Server stat",pop_server.stat())#打印出当前账号状态,第一个返回值为邮件数,第二个为占用空间
resp,mails,octets=pop_server.list()#获取所有邮件列表
print(mails)
index=len(mails)#获取最新的一封邮件(序号最大),邮件索引从1开始计数
resp,lines,octets=pop_server.retr(index)
msg_contnt=b'\r\n'.join(lines).decode("utf-8")
msg=Parser().parsestr(msg_contnt)#解析出邮件
pop_server.dele(index)#可以根据邮件索引号直接从服务器删除邮件
pop_server.quit()#关闭连接
如果正确连接上服务器并且列出邮件数量,说明已经正确使用了POP3协议并收到了邮件。
第一次运行:
又运行了一次:(邮件删除一封)
使用IMAP协议下载邮件(imaplib模块)
import imaplib
import email
username="1064800303@qq.com"#登录邮箱用户名
password="XXXXXX"#邮箱密码,SMTP授权码
imap_server=imaplib.IMAP4_SSL("imap.qq.com",993)#连接邮箱服务器
imap_server.login(username,password)#登录邮箱服务器
print("---------------LOG--------------")
imap_server.print_log()
print("--------------------------------")
resp,data=imap_server.list()#获取邮箱目录
print(data)
res,data=imap_server.select('INBOX')#选择默认收件箱并打印邮件数量
print(res,data)
print(data[0])
typ,lines=imap_server.fetch(data[0],'(RFC822)')#获取最新的一封邮件
msg=email.message_from_string(lines[0][1].decode('utf-8'))
imap_server.close()#关闭连接
解析邮件
解析邮件的过程正好和发送邮件构造邮件的过程相反,只要反向操作即可。
import poplib
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
username="1064800303@qq.com"#登录邮箱用户名
password="XXXXXXX"#邮箱密码,SMTP授权码
pop_server=poplib.POP3_SSL("pop.qq.com",995)#连接邮箱服务器
print(pop_server.getwelcome().decode("utf-8"))#打印出邮箱服务器的欢迎文字
pop_server.user(username)#登录邮箱服务器
pop_server.pass_(password)
print("Server stat",pop_server.stat())#打印出当前账号状态,第一个返回值为邮件数,第二个为占用空间
resp,mails,octets=pop_server.list()#获取所有邮件列表
print(mails)
index=len(mails)#获取最新的一封邮件(序号最大),邮件索引从1开始计数
resp,lines,octets=pop_server.retr(index)
msg_contnt=b'\r\n'.join(lines).decode("utf-8")
msg=Parser().parsestr(msg_contnt)#解析出邮件
pop_server.dele(index)#可以根据邮件索引号直接从服务器删除邮件
pop_server.quit()#关闭连接
def decode_email(s):
if not s:
return ""
value,charset=decode_header(s)[0]
if charset:
value=value.decode(charset)
return value
#打印邮件的发件人、收件人、主题
mail_from=msg.get("From","")
hdr,mail_from_addr=parseaddr(mail_from)
mail_from_name=decode_email(hdr)
print("发件人",mail_from_name,mail_from_addr)
mail_to=msg.get("To","")
hdr,mail_to_addr=parseaddr(mail_to)
mail_to_name=decode_email(hdr)
print("收件人",mail_to_name,mail_to_addr)
subject=decode_email(msg.get("Subject",""))
print("主题",subject)
def decode_mime(msg):#递归解析邮件
if msg.is_multipart():
parts=msg.get_payload()
for part in parts:
print(decode_mime(part))
else:
content_type=msg.get_content_type()
if content_type in ("text/plain","text/html"):
content=msg.get_payload(decode=True)
print(content)
else:
print("Attachement",content_type)
decode_mime(msg)
这封邮件运行后会在邮箱里被删除。