一、发送电子邮件
1.1、SMTP发送电子邮件
Python标准库提供了smtplib模块
,用于实现SMTP协议,发送邮件。标准库还提供了email模块
帮助我们构造邮件格式。
SMTP(Simple Mail Transfer Protocol,即简单邮件传输协议),是一组由源地址到目的地址传送邮件的规则,用来控制信件的中转方式。
Python的smtplib提供了一种发送电子邮件的方便途径,它会SMTP协议进行了简单的封装。
Python创建SMTP对象的语法为:
smtpObj = smtplib.SMTP([host [,port [,local_hostname]]])
参数说明:
- host:SMTP服务器主机,是可选参数。可以指定主机的IP地址或者域名,如:smtp.exmail.qq.com;
- port:如果提供了host参数,就需要指定SMTP服务使用的端口号,一般情况下SMTP的端口号为25;
- local_hostname:如果SMTP在自己的本机上,则只需要指定服务器地址为localhost即可;
Python SMTP对象使用sendmail方法发送邮件,语法如下:
SMTP.sendmail(from_addr,to_addrs,msg[,mail_options,rcpt_options])
参数说明:
- from_addr:邮件发送地址;
- to_addr:字符串列表,邮件接收地址;
- msg:发送消息,一般使用字符串
预备工作:开启SMTP和POP3服务,获取授权码
使用QQ邮箱发送邮件需要开启SMTP服务和POP3服务,SMTP协议用于发送邮件,POP3协议用于接收邮件,授权码用于连接到服务器。
1、登录邮箱->设置->账户
2、按要求发送短信验证,开启服务
3、开启服务之后就得到了授权码,此授权码不需要记,忘记了就关闭服务再开启服务即可
4、开启服务转态,如下图
import smtplib
from email.mime.text import MIMEText
from email.header import Header
#邮箱用户名
sender = "1178277540@qq.com"
#邮箱授权码
license = "ducdjgclcisahjdc"
#收件人
receicer = ["364336543@qq.com","wang_jc@126.com"]
#邮件正文
message = MIMEText("赳赳老秦,共赴国难!","plain","utf-8")
#发件人显式的名字
message["From"] = Header("嬴师隰","utf-8")
#收件人显式的名字
message["To"] = Header("嬴渠梁","utf-8")
#邮件标题
message["Subject"] = "一统天下"
try:
smtp = smtplib.SMTP_SSL("smtp.qq.com",465)
#登录
smtp.login(sender,license)
#发送
smtp.sendmail(sender,receicer,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("Error! 发送失败",e)
1.2、发送HTML格式的电子邮件
发送HTML格式的邮件,只要在使用MIMEText
函数构造邮件消息体的时候将第二个参数指定格式为“html”即可。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
#邮箱用户名
sender = "1178277540@qq.com"
#邮箱授权码
license = "ducdjgclcisahjdc"
#收件人
receicer = ["364336543@qq.com","wang_jc@126.com"]
#邮件正文
mail_msg = """
<h1>秦孝公招贤令</h1>
<p>昔我缪公自岐雍之间,修德行武。东平晋乱,以河为界。西霸戎翟,广地千里。天子致伯,诸侯毕贺,为后世开业,甚光美。</br>
会往者历、躁、简公、出子子不宁,国家内忧,未遑外事,三晋夺我先君河西地,诸侯卑秦,丑莫大焉。</br>
献公即位,镇抚边境,徙治栎阳,且欲东伐,复缪公之故地,修缪公之政令。寡人思念先君之意,常痛于心。宾客群臣有能出奇计强秦者,吾为尊官,与之分土。</p>
"""
message = MIMEText(mail_msg,"html","utf-8")
#发件人显式的名字
message["From"] = Header("嬴渠梁","utf-8")
#收件人显式的名字
message["To"] = Header("六国士子","utf-8")
#邮件标题
message["Subject"] = "幕贤强秦"
try:
smtp = smtplib.SMTP_SSL("smtp.qq.com",465)
#登录
smtp.login(sender,license)
#发送
smtp.sendmail(sender,receicer,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("Error! 发送失败",e)
1.3、发送带附件的邮件
附件其实就是另一种格式的MIME,所以在构造邮件消息体的时候需要使用MIMEMultipart
来构造复合类型的消息体,然后把文本和附件一个一个地加进去。
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
#邮箱用户名
sender = "1178277540@qq.com"
#邮箱授权码
license = "ducdjgclcisahjdc"
#收件人
receicer = ["364336543@qq.com","wang_jc@126.com"]
#指定消息体使用复合类型
message = MIMEMultipart()
#邮件正文
mail_msg = """
<h1>秦孝公招贤令</h1>
<p>昔我缪公自岐雍之间,修德行武。东平晋乱,以河为界。西霸戎翟,广地千里。天子致伯,诸侯毕贺,为后世开业,甚光美。</br>
会往者历、躁、简公、出子子不宁,国家内忧,未遑外事,三晋夺我先君河西地,诸侯卑秦,丑莫大焉。</br>
献公即位,镇抚边境,徙治栎阳,且欲东伐,复缪公之故地,修缪公之政令。寡人思念先君之意,常痛于心。宾客群臣有能出奇计强秦者,吾为尊官,与之分土。</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="main.py"'
message.attach(attached_file)
#发件人显式的名字
message["From"] = Header("嬴渠梁","utf-8")
#收件人显式的名字
message["To"] = Header("六国士子","utf-8")
#邮件标题
message["Subject"] = "一统天下"
try:
smtp = smtplib.SMTP_SSL("smtp.qq.com",465)
#登录
smtp.login(sender,license)
#发送
smtp.sendmail(sender,receicer,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("Error! 发送失败",e)
1.4、发送图片
我们都知道HTML网页可以嵌入诸如图片、视频等元素,自然在HTML格式的邮件中也可以嵌入这些内容,但是效果不好,因为大部分的邮件客户端和服务商都会屏蔽邮件正文的外部资源,像网页中的图片或者视频、音频等都是外部资源。
如果我们需要发送图片,只需把图片作为附件添加到邮件消息体中,然后在HTML格式的正文中使用src=cid:img1
格式嵌入即可。
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.header import Header
#邮箱用户名
sender = "1178277540@qq.com"
#邮箱授权码
license = "ducdjgclcisahjdc"
#收件人
receicer = ["364336543@qq.com","wang_jc@126.com"]
#指定消息体使用复合类型
message = MIMEMultipart("related")
#邮件正文
msg_content = MIMEMultipart("alternative")
mail_msg = """
<h1>秦孝公招贤令</h1>
<p>昔我缪公自岐雍之间,修德行武。东平晋乱,以河为界。西霸戎翟,广地千里。天子致伯,诸侯毕贺,为后世开业,甚光美。</br>
会往者历、躁、简公、出子子不宁,国家内忧,未遑外事,三晋夺我先君河西地,诸侯卑秦,丑莫大焉。</br>
献公即位,镇抚边境,徙治栎阳,且欲东伐,复缪公之故地,修缪公之政令。寡人思念先君之意,常痛于心。宾客群臣有能出奇计强秦者,吾为尊官,与之分土。</p>
"""
msg_content.attach(MIMEText(mail_msg,"html","utf-8"))
message.attach(msg_content)
#添加图片
with open("winterfall.jpg","rb") as f:
img1 = MIMEImage(f.read())
#定义资源的名字为img1
img1.add_header("Contend-ID","img1")
message.attach(img1)
#发件人显式的名字
message["From"] = Header("嬴渠梁","utf-8")
#收件人显式的名字
message["To"] = Header("六国士子","utf-8")
#邮件标题
message["Subject"] = "一统天下"
try:
smtp = smtplib.SMTP_SSL("smtp.qq.com",465)
#登录
smtp.login(sender,license)
#发送
smtp.sendmail(sender,receicer,message.as_string())
print("邮件已发送")
except smtplib.SMTPException as e:
print("Error! 发送失败",e)
二、接收电子邮件
接收邮件有两种常用的协议:POP3和IMAP协议
POP3协议:POP3协议(Post Office Protocol-Version 3,即邮局协议版本3)允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等)不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其它文件夹,邮件服务器上的这些邮件不会被同时移动。
IMAP协议:IMAP协议(Internet Mail Acess Protocol,即Internet邮件访问协议)提供Webmail与电子邮件客户端之间的双向通信,任何在客户端做的改变都会同步到服务器上。在客户端对邮件进行了操作,服务器上的邮件也会进行相应的操作。
同时,IMAP协议像POP3协议一样,提供了方便的邮件下载服务,让用户能够进行离线阅读。IMAP协议提供的摘要浏览功能可以让你在阅读完所有的邮件信息(到达时间、主题、发件人、大小等)后才作出是否下载的决定。此外,IMAP协议能更好地支持在多个不同设备上随时访问新邮件的功能。
2.1、使用POP3协议下载邮件
import poplib
from email.parser import Parser
#登录邮箱的用户名
username = "1178277540@qq.com"
#登录邮箱的密码
password = "ducdjgclcisahjdc"
#连接邮箱服务器
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)
#获取最新的一封邮件(序号最大的),邮件索引从1开始计数
index = len(mails)
resp,lines,octets = pop_server.retr(index)
msg_content = b'\r\n'.join(lines).decode("utf-8")
#解析出邮件
msg = Parser().parsestr(msg_content)
print(msg)
#可以根据邮件索引号直接从服务器删除邮件
pop_server.dele(index)
#关闭连接
pop_server.quit()
2.2、使用IMAP协议下载邮件
import imaplib
import email
#登录邮箱的用户名
username = "1178277540@qq.com"
#登录邮箱的密码
password = "ducdjgclcisahjdc"
#连接邮箱服务器
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()
2.3、解析邮件
import poplib
from email.parser import Parser
from email.header import Header
from email.utils import parseaddr
#登录邮箱的用户名
username = "1178277540@qq.com"
#登录邮箱的密码
password = "ducdjgclcisahjdc"
#连接邮箱服务器
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)
#获取最新的一封邮件(序号最大的),邮件索引从1开始计数
index = len(mails)
resp,lines,octets = pop_server.retr(index)
msg_content = b'\r\n'.join(lines).decode("utf-8")
#解析出邮件
msg = Parser().parsestr(msg_content)
print(msg)
#可以根据邮件索引号直接从服务器删除邮件
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_from_addr)
subject = decode_email(msg.get("Subject",""))
print("主题","")
#递归解析邮件
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)