python发邮件需要掌握两个模块的用法,smtplib和email。smtplib模块主要负责发送接收邮件,email模块主要负责构造邮件。
email模块下有mime包,mime英文全称为“Multipurpose Internet Mail Extensions”,该mime包下常用的有三个模块:text,image,multpart。
导入方法如下:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
构造一个邮件对象就是一个Message对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下。
常见的multipart类型有三种:multipart/alternative, multipart/related和multipart/mixed。
邮件类型为"multipart/alternative"的邮件包括纯文本正文(text/plain)和超文本正文(text/html)。
邮件类型为"multipart/related"的邮件正文中包括图片,声音等内嵌资源。
邮件类型为"multipart/mixed"的邮件包含附件。向上兼容,如果一个邮件有纯文本正文,超文本正文,内嵌资源,附件,则选择mixed类型。
from email.header import Header
subject = '中文标题'
subject=Header(subject, 'utf-8').encode()
Python对SMTP支持有 smtplib 和 email 两个模块,email 负责构造邮件,smtplib 负责发送邮件。
文本正文:
from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
HTML正文:
from email.mime.text import MIMEText
msg = MIMEText('test
'
, 'plain', 'utf-8')
import smtplib
from_addr = '189****[email protected]'
password = '*******'
to_addr = '[email protected]'
smtp_server = 'smtp.189.cn'
server = smtplib.SMTP_SSL(smtp_server, 465) # SMTP协议默认端口是465
server.set_debuglevel(1) # 打印出和SMTP服务器交互的所有信息
server.login(from_addr, password) # 登录SMTP服务器
server.sendmail(from_addr, [to_addr], msg.as_string()) # 发邮件
server.quit()
sendmail() 方法就是发邮件,由于可以一次发给多个人,所以传入一个 list,邮件正文是一个 str,as_string() 把MIMEText对象变成 str。
message = MIMEText(message_context, 'plain', 'utf-8')
# 设置发件人(声称的)
message["From"] = Header(sender_email_address, "utf-8")
# 设置收件人(声称的)
message["To"] = Header(receiver_email, "utf-8")
# 设置邮件主题
message["Subject"] = Header(message_subject, "utf-8")
# ccto_list 抄送
# bccto_list 暗送
msg['from'] = user
msg['to'] = ','.join(to_list) #注意,不是分号
msg['cc'] = ','.join(ccto_list)
msg['subject'] = subject
server.sendmail(sender,to_list+ccto_list+bccto_list, str(msg))
要想发送附件,需要构造一个 MIMEMultipart 对象代表邮件本身,然后往里面加上一个 MIMEText 作为邮件正文,再继续往里面加上表示附件的 MIMEBase 对象
sendfile=open(r'D:\pythontest\1111.txt','rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8')
text_att["Content-Type"] = 'application/octet-stream'
text_att["Content-Disposition"] = 'attachment; filename="显示的名字.txt"'
sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
image = MIMEImage(sendimagefile)
image.add_header('Content-ID','' )
#coding: utf-8
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.header import Header
#设置smtplib所需的参数
#下面的发件人,收件人是用于邮件传输的。
smtpserver = 'smtp.163.com'
username = '[email protected]'
password='XXX'
sender='[email protected]'
#receiver='[email protected]'
#收件人为多个收件人
receiver=['[email protected]','[email protected]']
subject = 'Python email test'
#通过Header对象编码的文本,包含utf-8编码信息和Base64编码信息。以下中文名测试ok
#subject = '中文标题'
#subject=Header(subject, 'utf-8').encode()
#构造邮件对象MIMEMultipart对象
#下面的主题,发件人,收件人,日期是显示在邮件页面上的。
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = '[email protected] '
#msg['To'] = '[email protected]'
#收件人为多个收件人,通过join将列表转换为以;为间隔的字符串
msg['To'] = ";".join(receiver)
#msg['Date']='2012-3-16'
#构造文字内容
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.baidu.com"
text_plain = MIMEText(text,'plain', 'utf-8')
msg.attach(text_plain)
#构造图片链接
sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
image = MIMEImage(sendimagefile)
image.add_header('Content-ID','' )
image["Content-Disposition"] = 'attachment; filename="testimage.png"'
msg.attach(image)
#构造html
#发送正文中的图片:由于包含未被许可的信息,网易邮箱定义为垃圾邮件,报554 DT:SPM :
html = """
Hi!
How are you?
Here is the link you wanted.
"""
text_html = MIMEText(html,'html', 'utf-8')
text_html["Content-Disposition"] = 'attachment; filename="texthtml.html"'
msg.attach(text_html)
#构造附件
sendfile=open(r'D:\pythontest\1111.txt','rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8')
text_att["Content-Type"] = 'application/octet-stream'
#以下附件可以重命名成aaa.txt
#text_att["Content-Disposition"] = 'attachment; filename="aaa.txt"'
#另一种实现方式
text_att.add_header('Content-Disposition', 'attachment', filename='aaa.txt')
#以下中文测试不ok
#text_att["Content-Disposition"] = u'attachment; filename="中文附件.txt"'.decode('utf-8')
msg.attach(text_att)
#发送邮件
smtp = smtplib.SMTP()
smtp.connect('smtp.163.com')
#我们用set_debuglevel(1)就可以打印出和SMTP服务器交互的所有信息。
#smtp.set_debuglevel(1)
smtp.login(username, password)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
import datetime
import imaplib
import email
def recv_email_by_imap4(self):
imap_server_host = 'imap.chinatelecom.cn'
# imap_server_host = 'imap.189.cn'
imap_server_port = 993
try:
imap = imaplib.IMAP4_SSL(host=imap_server_host, port=imap_server_port)
except Exception as e:
print(e)
try:
# 验证邮箱及密码是否正确
imap.login(self._email_addr, self._email_password)
except Exception as e:
print(e)
# 邮箱中其收到的邮件的数量
imap.select()
# 邮件状态设置,新邮件为Unseen
# Messagestatues = 'All,Unseen,Seen,Recent,Answered, Flagged'
resp, data = imap.search(None, "All")
# resp, data = imap.search(None, "Unseen")
index = data[0].decode().split()
number = 1
for i in data[0].split()[::-1]:
resp, mail_data = imap.fetch(i, "(RFC822)")
mail_text = mail_data[0][1].decode()
msg = email.message_from_string(mail_text)
if msg['Subject'] is not None:
subject = email.header.decode_header(msg["Subject"])
sub_fin = ''
for item in subject:
if item[1] is not None:
sub_fin += item[0].decode(item[1])
else:
sub_fin += str(item[0])
email_content, suffix = self.parse_email(msg)
# 命令窗体输出邮件基本信息
# 保存邮件正文
if (suffix != None and suffix != '') and (email_content != None and email_content != ''):
savefile(str(number) + suffix, email_content, self.mypath)
number = number + 1
# 关闭select
imap.close()
# 关闭连接
imap.logout()
解析邮件每部分内容,包括发邮件介绍的,text、html、附件、图片等
def parse_email(self, msg):
mail_content = None
#正文类型:text/plain、text/html
content_type = None
suffix = None
# 循环解析multipart
for part in msg.walk():
if not part.is_multipart():
content_type = part.get_content_type()
filename = part.get_filename()
charset = part.get_charset()
# 是否有附件
if filename:
dh = email.header.decode_header(filename)
name = dh[0][0]
encode_type = dh[0][1]
if encode_type is not None:
if charset is None:
name = name.decode(encode_type, 'gbk')
else:
name = name.decode(encode_type, charset)
data = part.get_payload(decode=True)
self.save_file(name, data)
else:
if content_type in ['text/plain']:
suffix = '.txt'
if content_type in ['text/html']:
suffix = '.htm'
if charset is None:
mail_content = part.get_payload(decode=True)
else:
mail_content = part.get_payload(decode=True).decode(charset)
return mail_content, suffix
def save_file(self, filename, data):
try:
file_path = self._path + filename
f = open(file_path, 'wb+')
f.write(data)
f.close()
except Exception as e:
print('filename error')
print(e)
f.close()