Posts 使用Python发送带有附件的邮件
Post
Cancel

使用Python发送带有附件的邮件

一、 前言

最近我的新网站仙交闲置公告版上线了, 为了更方便自己做运营, 需要每天检查网站的基本情况

直接查数据库固然不是难事, 但是作为一个日常工作, 还是让它变得自动一些为好, 于是乎我想到了把报告写到邮件中, 每天一次、以日报的方式发送给我, 这样就容易多了

所以我决定写一些python脚本辅助我, 首先是发送邮件

二、 正篇

找什么库做什么Google一下便知, 但实际操作起来的话还是有些细节需要注意

我在这里把必要的知识梳理一下, 希望对看官和以后忘掉的我有所帮助

废话不多讲了, 介绍一下本篇的两个库: smtplib模块, email模块

前者用来发邮件, 后者用来写邮件

2.1 配置

两个模块都是python标准库的成员, 所以只需直接导入, 貌似email模块要大一些, 所以采用from ... import ...的模式

下面是我的具体配置

1
2
3
4
import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart

MIME简介

何为MIME? MIME即Multipurpose Internet Mail Extensions(多用途互联网邮件扩展类型), 是用来对传统电子邮件进行拓展的标准, 也是目前电子邮件实际上的标准更多内容可以参考维基百科MDN文档

使用MIME的要点是选对独立类型, 就像操作系统通过文件拓展名判断打开方式一样, MIME的打开方式也依赖于其独立类型的声明

独立类型的格式是type(类型)/subtype(子类型), 下面是比较常用的例子

1
2
3
4
5
6
7
8
text/plain
text/html
image/jpeg
image/png
audio/mpeg
video/mp4
application/json
application/javascript

上面的例子也那囊括了五种类型(type), 前四种如字面意思, application表示数据是二进制数据, 但并没有将其限制为”可执行”, 它的子类型(subtype)可以是json/pdf/mspowepoint等

我们返回去看python的email模块, 就觉得清晰多了: text和application都是MIME的type, 而multipart用来整合邮件不同的MIME类型

这次我要发送的是带附件的html文本邮件, 所以用到了text和application两个类型

2.2 写邮件

首先是初始化, 创建一个包含不同MIME类型的邮件消息

1
message = MIMEMultipart()

然后像操作字典一样填写主题/from/to信息

1
2
3
4
# 主题 / from / to
message['Subject'] = 'XIB运营日报-{0}'.format(time_now_zh)
message['From'] = 'REINA.LINK'
message['to'] = "******@qq.com"

写好信封和题目, 接下来就是填充内容

  • 使用对应mime类型的函数读入数据, 添加一些选项和属性
  • 使用attach()函数接在已有的message上(如果邮件只有一种MIME类型则不需要使用Multipart, 自然也不用attach())
1
2
3
4
5
6
7
8
9
# 文本
txt = MIMEText(html_content, _subtype='html', _charset='utf-8')
message.attach(txt)

# 添加附件
attach_filename = os.path.split(attach_path)[1]
attachment = MIMEApplication(open(attach_path, 'rb').read())
attachment.add_header('Content-Disposition', 'attachment', filename = attach_filename)
message.attach(attachment)

至此邮件就写好了, 接下来轮到smtplib上场发邮件了

2.1 发邮件

在发送邮件之前, 我们先来了解一下SMTP

SMTP简介

什么是SMTP? 和邮箱有些交情的人应该比较熟悉, 在我们使用第三方代收/发邮件的时候, 往往需要开启SMTP服务; SMTP的全称是Simple Mail Transfer Protocol, 即”简单邮件传输协议”, 属于TCP/IP协议簇, 是一种在网络上传输邮件的标准, 用来控制邮件的中转方式更多内容可以参考阮一峰的网络日志维基百科

比较重要的几点就是:

  • 我们发送邮件需要遵循SMTP协议
  • SMTP需要认证, 使用专门的授权码, 并不是邮箱密码
  • 传统的SMTP并不安全, 现在大多采用SMTPS(即SSL加密的SMTP协议)

用例中的网易邮箱使用SMTPS, 经测试, 使用SMTP发送会卡在连接的那一步

首先定义一些服务器的信息

1
2
3
4
5
mail_host = 'smtp.163.com' # 网易的smtp服务器
mail_user = 'xxxxx@163.com' # 你的邮箱账号
mail_pass = '*************' # SMTP的授权码(在开通SMTP时获得)
sender = 'xxxxx@163.com' #最好和mail_user一致
receivers = ['929755067@qq.com'] # 可以有多个收信人

然后是连接、登录、发送、断开一条龙, 整体的思路是非常清晰的

注意传统SMTP的端口一般是25, SMTPS的端口是465

1
2
3
4
5
6
7
8
9
try:
    smtpObj = smtplib.SMTP_SSL(mail_host, 465)
    smtpObj.login(mail_user, mail_pass)
    smtpObj.sendmail(
        sender, receivers, message.as_string()
    )
    smtpObj.quit()
except smtplib.SMTPException as e:
    print('ERROR: ', e)

至此, 我使用email模块撰写并用smtplib成功发送了邮件; 其他邮箱和其他MIME类型的邮件就需要各位自己尝试了, 不过了解了思路/套路, 变更一下条件也只是查一下文档的事情了

This post is licensed under CC BY 4.0 by the author.