大家好,我是Samaritan。
如今Python非常热门,对于接触过的朋友可能最大的感受就是它的便利。大家应该都知道了如何使用smtplib和MIMEText轻易地发送一封普通的邮件,而在此基础上今天要分享的是如何构造附件内容,发送一封带有附件的邮件。
需要模块:smtplib和email.MIME
一、 模块介绍:
要完成发送邮件的行为,需要的功能肯定主要分为两部分:构造邮件和发送邮件。在python里我们可以使用2个自带的模块来实现,smtplib和email.mime,直接import导入即可,无需下载。
这里简单看一下官方文档的介绍:
smtplib —SMTP协议客户端
Source code: Lib/smtplib.py
The smtplib module defines an SMTP client session object that can be used to send mail to any Internet machine with an SMTP or ESMTP listener daemon. For details of SMTP and ESMTP operation, consult RFC 821 (Simple Mail Transfer Protocol) and RFC 1869 (SMTP Service Extensions).
SMTP (Simple Mail Transfer Protocol)翻译过来是“简单邮件传输协议”的意思,SMTP 协议是由源服务器到目的地服务器传送邮件的一组规则。显然smtplib可以简单理解为在代码中负责发送邮件的部分。我们会用到已下方法:
import smtplibserver = smtplib.SMTP()server.connect(host, port)server.login(username, password)server.sendmail(sender, to_addr, msg.as_string())server.quit()
接着再看email.mime:
email.mime: Creating email and MIME objects from scratch
Source code: Lib/email/mime/
This module is part of the legacy (Compat32) email API. Its functionality is partially replaced by the contentmanager in the new API, but in certain applications these classes may still be useful, even in non-legacy code.
Ordinarily, you get a message object structure by passing a file or some text to a parser, which parses the text and returns the root message object. However you can also build a complete message structure from scratch, or even individual Message objects by hand. In fact, you can also take an existing structure and add new Message objects, move them around, etc. This makes a very convenient interface for slicing-and-dicing MIME messages.
You can create a new object structure by creating Message instances, adding attachments and all the appropriate headers manually. For MIME messages though, the email package provides some convenient subclasses to make things easier.
通过邮件传输简单的文本已经无法满足我们的需求,比如我们时常会定制业务质量报表,在邮件主体中会包含 HTML、图像、声音以及附件格式等,MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)作为一种新的扩展邮件格式很好地补充了这一点。
所以在这里email.mime也就是代码中负责构造邮件内容的部分了。需要根据不同情况导入模块的功能,一般常用的有:
from email.header import Header# 用于构建邮件头from email.mime.text import MIMEText# 用于构建纯文本邮件内容from email.mime.image import MIMEImage# 用于处理图片from email.mime.multipart import MIMEMultipart# 用于处理多种形态的邮件主体from email.mime.application import MIMEApplication# 今天的主角,下面会说
二、具体实现:
使用代码来发送邮件往往是搭配我已经用代码处理和储存了文件,比如csv或是xlsx格式的表格,自动化办公时我需要它完成后给我发送邮件汇报,或者配合爬虫采集数据以后自动给我发送邮件等情景下。
下面单独列出构造带有附件的邮件代码,以通过qq邮箱发送一个表格为例,附上完整的源码和注释:
(windows环境下)
import smtplib# smtplib 用于邮件的发信动作from email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email.mime.application import MIMEApplication# 处理任意二进制文件if __name__ == \'__main__\':msg = MIMEMultipart()# 创建包含多个部分的邮件体的 MIME 对象实例user = \'xxx@qq.com\' # 发件人邮箱账号password = \'pwd\' # 发件人邮箱密码/授权码to_addr = \'xxx@163.com\' # 收件人地址smtp_serv = \'smtp.qq.com\' # 发信服务器msg[\'From\'] = Header(\"编辑发件人\", \'utf-8\')msg[\'To\'] = Header(\"编辑收件人\", \'utf-8\')msg[\'Subject\'] = Header(\'编辑邮件标题\', \'utf-8\')msg.attach(MIMEText(\'邮件正文文本内容\', _subtype=\'html\', _charset=\'utf-8\'))part = MIMEApplication(open(r\'C:\\Users\\data.xlsx\', \'rb\').read())# open里输入添加附件文件的绝对路径part.add_header(\'Content-Disposition\', \'attachment\', filename=\'data.xlsx\')# 构造附件,filename是编辑附件文件名,可以随便写msg.attach(part)# 添加附件server = smtplib.SMTP() # 开启发信服务(也可使用加密传输)server.connect(smtp_serv,25) # 连接服务器server.login(user, password) # 登录发信邮箱server.sendmail(user,to_addr, msg.as_string()) # 发送邮件server.quit() # 关闭服务器
好啦,以上就是完整的代码。
除了xlsx表格外,附件文件换成csv,或是图片png/jpg,音频mp3,视频mp4等都是一样可以用的。
三、补充事项:
首先,要使用smtp协议发送邮件,不要忘记去自己的邮箱设置中先开启服务。
仍然以我使用的qq邮箱为例:
在标示红框里开启服务,qq邮箱会验证并给你一个授权码,在代码里使用授权码作为password登录,这里请根据自己不同邮箱实际情况设置(比如我网易邮箱就直接使用的密码)
其次,常规报错,如果你复制了我的源码但是出现以下情况不能使用:
报错ValueError: server_hostname cannot be an empty string or start with a leading dot.
解决方法:
# 使用ssl加密发信服务server = smtplib.SMTP_SSL()# 在括号内加入host参数,对应正确的端口号server = smtplib.SMTP_SSL(smtp_server)
报错smtplib.SMTPException: No suitable authentication method found
解决方法:
你用的是QQ以外的其他邮箱,比如利用企业邮箱,可能会出现这种报错。
在登录(login)之前调用starttls()方法就可以了。也就是在代码中加入这样一行:
server.starttls()
很多问题已经有前辈大神们讲的非常细了,这里不再赘述,遇到问题通过合理的搜索都可以迎刃而解。
最后,对使用今天的主角MIMEApplication做个解释:
由于MIME有很多种类型,上述之展示了部分常用情况,如果附件是图片格式,我要用MIMEImage,如果是音频,要用MIMEAudio,如果是word、excel,我都不知道该用哪种MIME类型了还要去搜索。
既然是实用向,我们采取最懒的方法就是,不管什么类型的附件,都用MIMEApplication,MIMEApplication默认子类型是application/octet-stream。
application/octet-stream表明“这是个二进制的文件,希望你们那边知道怎么处理”,然后客户端,比如qq邮箱,收到这个声明后,会根据文件扩展名来猜测。
这样是不是就很方便了呢?
以上,
本次的内容就到这里了,如果对你有用的话我会很开心~
照旧,最近还在研究爬虫。
欢迎和我一起讨论python和爬虫,如有大佬不吝赐教,无比感谢。