01
发送邮件
发送邮件使用SMTP协议【Simple Mail Transfer Protocol简单的邮件传输协议】,SMTP协议是SMTP客户端与SMTP服务器之间的通信协议。
python中发送邮件使用的模块有smtplib和email:
1.使用smtplib模块进行发送邮件;
2.使用email模块来添加发送的邮件内容。
1. smtplib模块
导入模块:import smtplib
1.1. 创建SMTP对象
smtplib.SMTP和smtplib.SMTP_SSL:均可以用来创建SMTP对象;
smtplib.SMTP_SSL:使用安全加密的SSL协议连接到SMTP服务器;
smtplib.SMTP:没有进行安全加密。
故若待测试邮箱不允许使用非SSL和非TLS频道通信时,则无法使用smtp.SMTP方式来创建客户端对象。
【查看邮箱的通信方式:邮箱设置菜单中,查看邮箱的接收服务器和发送服务器信息。】
如:腾讯企业邮箱接收服务器:imap.exmail.qq.com(使用SSL,端口号993)发送服务器:smtp.exmail.qq.com(使用SSL,端口号465)
-
smtplib.SMTP(host,port,local_hostname,timeout,source_address)
-
smtplib.SMTP_SSL(host, port, local_hostname, keyfile, certfile, timeout, source_address, context)
创建SMTP对象。
host:SMTP发送服务器主机
port:SMTP服务器端口号
1.2. SMTP对象操作
-
login(user, password, *, initial_response_ok=True)
SMTP对象登录
user:授权登录的用户名
password:授权登录的密码
-
sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])
SMTP对象发送邮件
from_addr:发件人地址,字符串类型。
to_addr:收件人地址,包括收件人和抄送人。
多个收件人时to_addr参数为列表,单个收件人时to_addr参数可以为列表或字符串。
msg:要发送的信息
-
quite终止SMTP会话
2. 发送邮件的实例
2.1. 添加邮件内容,包括收件人、抄送人、正文、附件
from email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email.mime.text import MIMETextfrom email.mime.image import MIMEImageimport osclass EmailContent:def __init__(self, senderAdr, emailSubject, toReceivers, ccReceivers):# 邮件对象self.msg = MIMEMultipart# 添加发件人头self.msg[’From’] = Header("测试" + "<" + senderAdr + ">", ’utf-8’)# 添加收件人if isinstance(toReceivers, str):self.msg["To"] = toReceiverselif isinstance(toReceivers, list):self.msg[’To’] = ";".join(toReceivers)# 添加抄送人if isinstance(ccReceivers, str):self.msg["Cc"] = ccReceiverselif isinstance(ccReceivers, list):self.msg["Cc"] = ";".join(ccReceivers)# 添加邮件主题self.msg[’Subject’] = Header(emailSubject, "utf-8")def addBody(self, bodyType):"""添加不同的邮件正文的实例1. body为字符串:(如)"这是一个邮件正文内容"2. body为html格式的字符串:(如)"<div><p>第一段</p><p> 第二段</p></div>"3. body正文中包含有图片:"""if bodyType == "string":body = "这是一个邮件正文内容"mimeText = MIMEText(body, "plain", "utf-8")self.msg.attach(mimeText)elif bodyType == "html":body = "<div><p>第一段</p><p> 第二段</p></div>"mimeText = MIMEText(body, "html", "utf-8")self.msg.attach(mimeText)elif "image" in bodyType:imageFile = "E://log//test.png"imageId = os.path.split(imageFile)[1]# 添加内容body = ’’’<p>测试图片为:</p><p><img src="cid:{imageId}"></p>’’’.format(imageId=imageId)mimeText = MIMEText(body, "html", "utf-8")self.msg.attach(mimeText)# 读取图片,并设置图片id用于邮件正文引用with open(imageFile, "rb") as fp:mimeImage = MIMEImage(fp.read)mimeImage.add_header("Content-ID", imageId)self.msg.attach(mimeImage)def addAttachment(self, attachmentName):"""添加附件:return:"""file = "E://log//test.txt"# file = "E://log//test.zip"# file = "E://log//test.png"filePath, fileName = os.path.split(file)print("fileName =", fileName)enclosure = MIMEText(open(file, ’rb’).read, ’base64’, ’utf-8’)enclosure[’Content-Type’] = ’application/octet-stream’if attachmentName == "英文":enclosure[’Content-Disposition’] = ’attachment; filename="%s"’ % fileNameelif attachmentName == "中文":enclosure.add_header("Content-Disposition", "attachment", filename=("gbk", "", fileName))self.msg.attach(enclosure)
2.2. 发送邮件
import smtplibdef SendEmail:"""发送邮件"""# SMTP的服务器信息smtpHost = "smtp.exmail.qq.com"sslPort = 465senderAdr = "xx@xx.cn"senderPwd = "XXXX"# 创建SMTP对象smtpServer = smtplib.SMTP_SSL(smtpHost, sslPort)# # 设置debug模块# smtpServer.set_debuglevel(True)# 登录smtpServer.login(senderAdr, senderPwd)# 添加邮件内容toReceivers = ["a@xx.cn", "b@xx.cn"]ccReceivers = ["d@xx.cn", "e@xx.cn"]toAddrs = toReceivers + ccReceiversemailSubject = "这是个编程技术圈自动发送的邮件"emailContent = EmailContent(senderAdr, emailSubject, toReceivers, ccReceivers)emailContent.addBody("html")emailContent.addAttachment("英文")message = emailContent.msg# 发送smtpServer.sendmail(senderAdr, toAddrs, message.as_string)# 终止SMTP会话smtpServer.quitSendEmail
02
读取邮件
收取邮件使用POP3协议;
解析邮件:需要将收取的邮件转化为email.message.Message对象,再使用email模块解析内容。
1. 读取邮件的实例
1.1. 获取某封邮件的对象
import poplibfrom email.parser import Parser"""POP的服务器信息"""popHost = "pop.exmail.qq.com"userAdr = "xx@xx.cn"userPwd = "xxxxx"""" 创建POP3对象,添加用户名和密码"""pop3Server = poplib.POP3(popHost)pop3Server.user(userAdr)pop3Server.pass_(userPwd)"""获取邮件数量和占用空间"""messageCount, mailboxSize = pop3Server.stat"""获取邮件请求返回状态码、每封邮件的字节大小(b’第几封邮件 此邮件字节大小’)、"""response, msgNumOctets, octets = pop3Server.list""" 获取任意一封邮件的邮件对象【第一封邮件的编号为1,而不是0】"""msgIndex = random.randint(1,messageCount)print(msgIndex)# 获取第msgIndex封邮件的信息response, msgLines, octets = pop3Server.retr(msgIndex)# msgLines中为该邮件的每行数据,先将内容连接成字符串,再转化为email.message.Message对象msgLinesToStr = b"\r\n".join(msgLines).decode("utf8", "ignore")messageObject = Parser.parsestr(msgLinesToStr)print(messageObject)""" 终止POP3服务"""pop3Server.quit
1.2. 解析邮件对象
1.2.1. 获取邮件日期
msgDate = messageObject["date"]print(msgDate)
1.2.2. 获取邮件发件人实名、邮箱地址
获取邮件实名时,名称一般是加密的,此时就需要对头文件进行解码才可获取它的实际内容
from email.header import decode_headerdef decodeMsgHeader(header):"""解码头文件:param header: 需解码的内容:return:"""value, charset = decode_header(header)[0]if charset:value = value.decode(charset)return value
from email.utils import parseaddrsenderContent = messageObject["From"]# parseaddr函数返回的是一个元组(realname, emailAddress)senderRealName, senderAdr = parseaddr(senderContent)# 将加密的名称进行解码senderRealName = decodeMsgHeader(senderRealName)print(senderRealName)print(senderAdr)
1.2.3. 获取邮件主题
获取的邮件的主题也是加密的,此时就需要对头文件进行解码才可获取它的实际内容
msgHeader = messageObject["Subject"]# 对头文件进行解码msgHeader = decodeMsgHeader(msgHeader )print(msgHeader)
1.2.4. 获取邮件正文
一封邮件的正文内容,可能是由几部分构成,每部分的格式不同。
"""获取邮件正文内容"""msgBodyContents =if messageObject.is_multipart: # 判断邮件是否由多个部分构成messageParts = messageObject.get_payload # 获取邮件附载部分for messagePart in messageParts:bodyContent = decodeBody(messagePart)if bodyContent:msgBodyContents.append(bodyContent)else:bodyContent = decodeBody(messageObject)if bodyContent:messageBodyContents.append(bodyContent)print(msgBodyContents)
def decodeBody(msgPart):"""解码内容:param msgPart: 邮件某部分"""contentType = msgPart.get_content_type # 判断邮件内容的类型,text/htmltextContent = ""if contentType == ’text/plain’ or contentType == ’text/html’:content = msgPart.get_payload(decode=True)charset = msgPart.get_charsetif charset is None:contentType = msgPart.get(’Content-Type’, ’’).lowerposition = contentType.find(’charset=’)if position >= 0:charset = contentType[position + 8:].stripif charset:textContent = content.decode(charset)return textContent
1.2.5. 获取邮件附件
邮件附件名为中文时,需借助头文件解码方式进行解码,否则会为乱码。
messageAttachments =if messageObject.is_multipart: # 判断邮件是否由多个部分构成messageParts = messageObject.get_payload # 获取邮件附载部分for messagePart in messageParts:name = messagePart.get_param("name") # 名字存在,则表示此部分为附件if name:fileName = decodeMsgHeader(name) # 解码messageAttachments.append(fileName)else:name = messageObject.get_param("name")if name:fileName = decodeMsgHeader(name) # 解码messageAttachments.append(fileName)print(messageAttachments)
2. 读取邮件时遇到的问题
2.1. 提示“poplib.error_proto: line too long”
File "XXX/EmailInfo.py", line 22, in getMessageObjectreturn parser.Parser.parsestr(b"\n".join(self.popServer.retr(i)[1]).decode("utf8", "ignore"))File "/usr/local/lib/python3.6/poplib.py", line 248, in retrreturn self._longcmd(’RETR %s’ % which)File "/usr/local/lib/python3.6/poplib.py", line 183, in _longcmdreturn self._getlongrespFile "/usr/local/lib/python3.6/poplib.py", line 168, in _getlongrespline, o = self._getlineFile "/usr/local/lib/python3.6/poplib.py", line 130, in _getlineraise error_proto(’line too long’)poplib.error_proto: line too long
POP3对行长度做了限制,默认为_MAXLINE = 2048,故若是邮件超过此长度就会提示“poplib.error_proto: line too long”。
解决方案:在读取邮件代码中重新定义最大行长度,即给poplib._MAXLINE设置新值。
import poplibpoplib._MAXLINE=20480
- end -
