python的邮件模块对于周期性邮件发送(如日报、周报)是非常高效的,搭配time库还能实现定时发送,搭配pandas、matplotlib可实现数据分析、可视化和报表发送的全流程自动化,对于工作效率提升有极高价值,本文简要介绍邮件模块的基本实现。
一、详细步骤
1.前提
- 设置邮箱的安全权限(设置为低)或者使用一个随机账号邮箱
- 设置gmail该页允许captcha,从而让python可以登录该gmail
2.载入库
smtplib(控制服务器通信)、mimetext(控制邮件的内容)、mimemultipart(控制邮件的样式和结构)
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
import smtplib
3. 库的使用
smtplib
- 建立连接
server = smtplib.SMTP(host='smtp.163.com', port=25)
创建一个SMTP连接实例
国内邮箱port一般为25
- 向ESMTP服务器标识身份(可选)
SMTP.ehlo(name='')
该方法可选,一般可在在send_mail
方法中调用,name默认为本地主机名。
若是SMTP服务器则使用
helo()
方法
- 设置SMTP的联结模式,默认为TLS(Transport Layer Security)
SMTP.starttls(keyfile=None, certfile=None, context=None)
使用后,所有smtp命令都会被编码 - 登陆
SMTP.login(user, password, *, initial_response_ok=True)
- 发送邮件
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
发送邮件,必须要有收件人和发件人地址,和一个信息字符串。from_addr放一个邮箱,to_addrs放一个邮箱列表。
如果没有明确定义
EHLO
或HELO
,则会优先使用ESMP测试服务器
- 终止进程并关闭连接
SMTP.quit()
MIMEMultipart
class email.mime.multipart.MIMEMultipart(_subtype=‘mixed’, boundary=None, _subparts=None, *, policy=compat32, **_params)
- _subtype
子类型,控制结构,一共三种可选,见下图,默认为mixed
[image:F03CCC37-27D0-4243-B4B5-54225B6F4231-1376-0000A5E6CF0A5887/FBCC8C1A-E79A-44F4-86AA-B1CE0D6ABA26.png]
msg = MIMEMultipart('alternative')
- _subparts
控制初始化的内容,可以通过attach
添加,如先用mimetext创建了对象,再添加到mimemultipart对象后
if html != 'None':
html_part = MIMEText(html, 'html')
msg.attach(html_part)
对于html,需要一个完整的html模块来实现,可参考前端的html格式,同时可以借助pd中的to_html函数将任何类型的数据转换成html然后以html放入邮件中
- _params
是关键字参数,可以通过字典赋值,如果没有设置,则在发件人和收件人的显示上仅显示邮箱和内容,没有主题和发件人收件人名称
msg = MIMEMultipart('alternative')
msg['To'] = ', '.join(to_email)
msg['Subject'] = subject
msg['From'] = from_email
其他关键字
[image:FCE83CEA-6538-4487-921C-2373B2521D15-1376-0000A70D9B96B2D4/715A658B-00BC-4D1B-A352-54AC2EBD56D2.png]
MIMEText
class email.mime.text.MIMEText(_text, _subtype=‘plain’, _charset=None, *, policy=compat32)
_text
即变量名,_subtype
为子类型,可以是html、plain等
MIMEApplication
class email.mime.application.MIMEApplication(_data, _subtype=‘octet-stream’, _encoder=email.encoders.encode_base64, *, policy=compat32, **_params)
此处_data
是 attachment.read()
如果要更换可以使用set_payload
更换内容
MIMEBase(基类)
实现附件添加
class email.mime.base.MIMEBase(_maintype, _subtype, *, policy=compat32, **_params)
- _maintype
主类型(内容),例如是文本还是图像
[image:80F4AF5B-C960-405F-86EB-A1A03D6AF884-1376-0000AC0074BDF04C/7073B2C3-D0C8-4E1C-865D-1AEC6F2EDAE9.png]
[image:1F93C5C6-4C7A-4713-870E-69FC02257BDE-1376-0000BC7E806EFCCF/39E37A0C-FE13-4D0B-A78F-1B6636DA4928.png]
其中application
是指主类型,x-zip-compressed
是其一个子类型
可写作:
part = MIMEBase(‘application’, ‘x-zip-compressed’)
——即zip文件类型
常见主类型、子类型
[image:682DEEFD-B943-4688-894C-52541E3B618D-1376-0000AC3BD9B3F004/A52C6262-EB06-43BD-AA96-226F89BBD7A5.png]
- _subtype
子类型,例如文本的格式是plain,图像的格式是gif - _params
关键字参数,键值字典,可以通过add_header添加
part.add_header('Content-Dispostition', 'attachment; file_name =%s%'file_name)
添加一个附件
file_name = os.path.basename(file_location)
attachment = open(file_location, 'rb') # 创建对象
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read()) # 添加有效载重
encoders.encode_base64(part)
part.add_header('Content-Dispostition', 'attachment; file_name =%s%'file_name)
msg.attach(part)
二、总结
- 文件路径导入os读取文件名→
- 读取文件路径并将读取文件内容存储到变量中→
- 创建一个MIMEBase对象(设置参数)→
- m对象加载刚刚存储的文件变量→
- 给m对象添加参数告诉它要把文件以何名放在何处→
- 将m对象添加到multipart对象中去
对于不同的文件一定要选择不同的主类型和子类型,否则传输过程中会出错导致最终结果有误;另外如果要添加附件,参数一定要换成
mixed
附:源码
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os.path
username = 'finnli1991@163.com'
password = 'UTRKSWKDNSHJGSFO'
def send_mail(
text='Email Body', subject='Hello world',
from_email='Finn li <finnli1991@163.com>',
to_email=None, html=None, file_location=None):
assert isinstance(to_email, list)
msg = MIMEMultipart('alternative')
msg['To'] = ', '.join(to_email)
msg['Subject'] = subject
msg['From'] = from_email
txt_part = MIMEText(text, 'plain')
msg.attach(txt_part)
if html != 'None':
html_part = MIMEText(html, 'html')
msg.attach(html_part)
msg_str = msg.as_string()
file_name = os.path.basename(file_location)
attachment = open(file_location, 'rb')
# 创建对象
part = MIMEBase('application', 'octet-stream')
# 添加有效载重
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Dispostition', 'attachment; file_name =%s%'file_name)
msg.attach(part)
# 登录smtp服务器
server = smtplib.SMTP(host='smtp.163.com', port=25)
server.ehlo()
server.starttls()
server.login(username, password)
server.sendmail(from_email, to_email, msg_str)
server.quit()