SMTP是发送邮件的协议,Python 2.3版本开始内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。本文以QQ邮件为例,用python发送各类邮件。

Python对SMTP支持主要使用smtplib和email两个模块,email模块负责构造邮件,smtplib模块负责发送邮件。

一、 传输简单邮件 smtplib模块

1. SMTP类定义

smtplib.SMTP([host[,port[,local_hostname[,timeout]]]])

作为SMTP的构造函数,功能是与smtp服务器建立连接,在连接成功后,就可以向服务器发送相关请求,比如登录、校验、发送、退出等。

  • host参数为远程smtp主机地址,比如smtp.163.com
  • port为连接端口,默认为25
  • local_hostname的作用是在本地主机的FQDN(完整的域名)发送HELO/EHLO(标识用户身份)指令
  • timeout为连接或尝试在多少秒超时

由于安全问题,通常不直接使用smtplib.SMTP来实例化,第三方邮箱会认为它是不安全的而报错。使用加密过的SMTP_SSL来实例化,它负责让服务器做出具体操作,它有两个参数:

  • 参数1:smtp服务器地址,但它是bytes格式,所以需要编码
  • 参数2:smtp端口,SMTP_SSL协议默认端口是465
smtp_srv = "smtp.qq.com"
srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)

2. SMTP类方法

  • SMTP.connect([host[,port]]):连接远程smtp主机

host为远程主机地址,port为远程主机smtp端口,也可以直接使用host:port形式来表示

SMTP.connect("smtp.163.com","25")
  • SMTP.login(user, password):远程smtp主机的校验方法

参数为用户名与密码(或者授权码,视邮箱而定)

SMTP.login("python_2014@163.com","sdjkg358")
  • SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options]):实现邮件的发送功能

参数依次为是发件人、收件人(列表)、邮件内容

SMTP.sendmail("python_2014@163.com",["demo@domail.com","demo@domail02.com"],body)
  • SMTP.starttls([keyfile[, certfile]]):启用TLS(安全传输)模式

所有SMTP指令都将加密传输,例如使用gmail的smtp服务时需要启动此项才能正常发送邮件,如SMTP.starttls()。

  • SMTP.quit():断开smtp服务器的连接

二、 定制个性化邮件 email模块

除简单文本外,很多时候邮件中还会包含HTML、图片、音频、附件等。MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)作为一种新的扩展邮件格式很好地补充了这一点。

可以将email.mime理解成smtplib模块邮件内容主体的扩展,从原先默认只支持纯文本格式扩展到HTML,同时支持附件、音频、图像等格式,smtplib只负责邮件的投递即可。

下面介绍几个常用的MIME实现类:

  • email.mime.multipart.MIMEMultipart([_subtype[,boundary[,_subparts[,_params]]]])包含多个部分邮件体的MIME对象。

参数_subtype指定要添加到 "Content-type:multipart/subtype" 报头的三种可选子类型:

mixed(默认):构建一个带附件的邮件体
related:构建内嵌资源的邮件体
alternative:构建纯文本与超文本共存的邮件体
  • email.mime.audio.MIMEAudio (_audiodata[,_subtype[,_encoder[,**_params]]]):创建包含音频数据的邮件体

_audiodata包含原始二进制音频数据的字节字符串。

  • email.mime.image.MIMEImage(_imagedata[,_subtype[,_encoder[,**_params]]]):创建包含图片数据的邮件体

_imagedata是包含原始图片数据的字节字符串。

  • email.mime.text.MIMEText (_text[,_subtype[,_charset]]):创建包含文本数据的邮件体

_text是包含消息负载的字符串,_subtype指定文本类型,支持plain(默认值)或html类型的字符串。

三、发送简单文本邮件

下面是一个小例子,只简单发送文本数据

1. 获取授权码

进入QQ 邮箱的主界面→设置→账户,开启“POP3/SMTP服务”和“IMAP/SMTP 服务”。

开启后会弹出授权码,记录下来,例如

  • POP3/SMTP服务:kkkkkkkkkkkkkk
  • IMAP/SMTP服务:jjjjjjjjjjjjjjjjjjjjjjjjjjj

2. Python代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#@Time  : 2022/2/5 23:03
#@File  : python_email.py

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# 发件人
from_name = "Hehuyi_In"
# 发件邮箱
from_addr = "xxxxx@qq.com"
# 发件邮箱授权码,注意不是QQ邮箱密码
from_pwd = "jjjjjjjjjj"
# 收件邮箱
to_addr = "yyyyyy@qq.com"

# 邮件标题
my_title = "Hehuyi Test"
# 邮件正文
my_msg = "Hello World"

# MIMEText三个主要参数
# 1. 邮件内容
# 2. MIME子类型,plain表示text类型
# 3. 邮件编码格式,使用"utf-8"避免乱码
msg = MIMEText(my_msg, 'plain', 'utf-8')
msg['From'] = formataddr([from_name, from_addr])
# 邮件的标题
msg['Subject'] = my_title

# SMTP服务器地址,QQ邮箱的SMTP地址是"smtp.qq.com"
smtp_srv = "smtp.qq.com"

try:
    # 不能直接使用smtplib.SMTP来实例化,第三方邮箱会认为它是不安全的而报错
    # 使用加密过的SMTP_SSL来实例化,它负责让服务器做出具体操作,它有两个参数
    # 第一个是服务器地址,但它是bytes格式,所以需要编码
    # 第二个参数是服务器的接受访问端口,SMTP_SSL协议默认端口是465
    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)

    # 使用授权码登录QQ邮箱
    srv.login(from_addr, from_pwd)

    # 使用sendmail方法来发送邮件,它有三个参数
    # 第一个是发送地址
    # 第二个是接受地址,是list格式,可以同时发送给多个邮箱
    # 第三个是发送内容,作为字符串发送
    srv.sendmail(from_addr, [to_addr], msg.as_string())
    print('发送成功')
except Exception as e:
    print('发送失败')
finally:
    #无论发送成功还是失败都要退出你的QQ邮箱
    srv.quit()

执行代码

 注意Python文件名不能和import的包名相同,否则会遇到以下报错

E:\Python36\python.exe E:/pytest/email.py

Traceback (most recent call last):

  File "E:/pytest/email.py", line 7, in <module>

    import smtplib

  File "E:\Python36\lib\smtplib.py", line 47, in <module>

    import email.utils

  File "E:\pytest\email.py", line 8, in <module>

    from email.mime.text import MIMEText

ModuleNotFoundError: No module named 'email.mime'; 'email' is not a package

Process finished with exit code 1

查看QQ邮箱,发现果然收到了新邮件,并且标题、发件人、正文都跟我们设置的一样

四、 发送HTML格式邮件

本示例通过引入email.mime的MIMEText类来实现支持HTML格式的邮件,支持所有HTML元素,包含表格、图片、动画、CSS样式、表单等。使用HTML的表格定制美观的业务报表:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time  : 2022/2/5 23:03
# @Author: Hehuyi_In
# @File  : html_email.py

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# 发件人
from_name = "Hehuyi_In"
# 发件邮箱
from_addr = "xxxxxxx@qq.com"
# 发件邮箱授权码,注意不是QQ邮箱密码
from_pwd = "jjjjjjj"
# 收件邮箱
to_addr = "xxxxxxx@qq.com"

# 邮件标题
my_title = "HTML Test"
# 邮件正文,html格式
my_msg = '''
    <table width="800" border="0" cellspacing="0" cellpadding="4">
      <tr>
          <td bgcolor="#CECFAD" height="20" style="font-size:14px">*官网数据 <a href="monitor.domain.com">更多>></a></td>
      </tr>
      <tr>
        <td bgcolor="#EFEBDE" height="100" style="font-size:13px">
        1)日访问量:<font color=red>152433</font> 访问次数:23651 页面浏览量:45123 点击数:545122 数据流量:504Mb<br>
        2)状态码信息<br>
        &nbsp;&nbsp;500:105 404:3264 503:214<br>
        3)访客浏览器信息<br>
        &nbsp;&nbsp;IE:50% firefox:10% chrome:30% other:10%<br>
        4)页面信息<br>
        &nbsp;&nbsp;/index.php 42153<br>
        &nbsp;&nbsp;/view.php 21451<br>
        &nbsp;&nbsp;/login.php 5112<br>
        </td>
      </tr>
    </table>'''

# 参数2改为html
msg = MIMEText(my_msg, 'html', 'utf-8')
msg['From'] = formataddr([from_name, from_addr])
# 邮件的标题
msg['Subject'] = my_title

# SMTP服务器地址
smtp_srv = "smtp.qq.com"

try:
   
    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)

    # 使用授权码登录QQ邮箱
    srv.login(from_addr, from_pwd)

    # 使用sendmail方法来发送邮件
    srv.sendmail(from_addr, [to_addr], msg.as_string())
    print('发送成功')
except Exception as e:
    print('发送失败')
finally:
    # 无论发送成功还是失败都要退出你的QQ邮箱
    srv.quit()

运行结果

五、 发送图文格式邮件

当要求包含图片数据的邮件内容时,需要引用MIMEImage类,若邮件主体由多个MIME对象组成,则同时需引用MIMEMultipart类来进行组装。

本示例通过MIMEText与MIMEImage类的组合来实现图文格式邮件的定制:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time  : 2022-02-07 22:00
# @Author: Hehuyi_In
# @File  : image_email.py

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.utils import formataddr

# 发件人
from_name = "Hehuyi_In"
# 发件邮箱
from_addr = "xxxx@qq.com"
# 发件邮箱授权码,注意不是QQ邮箱密码
from_pwd = "xxxxx"
# 收件邮箱
to_addr = "xxxx@qq.com"
# 邮件标题
my_title = "HTML+Image Test"

# 添加图片函数,参数1:图片路径,参数2:图片id
def addimg(src,imgid):
    fp = open(src,'rb')  # 打开文件
    msg_image = MIMEImage(fp.read())  # 创建MIMEImage对象,读取图片内容并作为参数
    fp.close() # 关闭文件
    msg_image.add_header('Content-ID',imgid)  # 指定图片文件的Content-ID,<img>标签src用到
    return  msg_image

# 创建MIMEMultipart对象,采用related定义内嵌资源的邮件体
msg_multipart = MIMEMultipart('related')

# 创建MIMEText对象,HTML元素包括表格<table>及图片<img>
msg_text = MIMEText("""
<table width="600" border="0" cellspacing="0" cellpadding="4">
      <tr bgcolor="#CECFAD" height="20" style="font-size:14px">
        <td colspan=2>*SqlServer001 <a href="monitor.domain.com">更多>></a></td>
      </tr>
      <tr bgcolor="#EFEBDE" height="100" style="font-size:13px">
        <td>
         <img src="cid:001"></td><td> 
         <img src="cid:002"></td>
      </tr>
      <tr bgcolor="#EFEBDE" height="100" style="font-size:13px">
        <td>
        <img src="cid:003"></td><td>
        <img src="cid:004"></td>
      </tr>
</table>""","html","utf-8")   # <img>标签的src属性是通过Content-ID来引用的

# MIMEMultipart对象附加MIMEText及MIMEImage的内容
msg_multipart.attach(msg_text)
msg_multipart.attach(addimg("img/001.png","001"))  # 图片路径与标签,001对应上方html中的<img src="cid:001">
msg_multipart.attach(addimg("img/002.png","002"))
msg_multipart.attach(addimg("img/003.png","003"))
msg_multipart.attach(addimg("img/004.png","004"))

# 发件人
msg_multipart['From'] = formataddr([from_name, from_addr])
# 邮件标题
msg_multipart['Subject'] = my_title

# SMTP服务器地址
smtp_srv = "smtp.qq.com"

try:

    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)

    # 使用授权码登录QQ邮箱
    srv.login(from_addr, from_pwd)

    # 使用sendmail方法来发送邮件
    srv.sendmail(from_addr, [to_addr], msg_multipart.as_string())
    print('发送成功')
except Exception as e:
    print('发送失败')
finally:
    # 无论发送成功还是失败都要退出你的QQ邮箱
    srv.quit()

运行结果如图

六、 发送带附件的邮件

本示例通过MIMEText与MIMEImage类的组合,实现图文邮件格式,另通过MIMEText类再定义Content-Disposition属性来实现带附件的邮件。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time  : 2022-02-07 22:33
# @Author: Hehuyi_In
# @File  : attach_email.py

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.utils import formataddr

# 发件人
from_name = "Hehuyi_In"
# 发件邮箱
from_addr = "xxxx@qq.com"
# 发件邮箱授权码,注意不是QQ邮箱密码
from_pwd = "xxxxx"
# 收件邮箱
to_addr = "xxxx@qq.com"
# 邮件标题
my_title = "Text+Image+Attachment Test"

# 添加图片函数,参数1:图片路径,参数2:图片id
def addimg(src,imgid):
    fp = open(src,'rb')  # 打开文件
    msg_image = MIMEImage(fp.read())  # 创建MIMEImage对象,读取图片内容并作为参数
    fp.close() # 关闭文件
    msg_image.add_header('Content-ID',imgid)  # 指定图片文件的Content-ID,<img>标签src用到
    return  msg_image

# 创建MIMEMultipart对象,采用related定义内嵌资源的邮件体
msg_multipart = MIMEMultipart('related')

#创建一个MIMEText对象,HTML元素包括文字与图片<img>
msg_text = MIMEText("<font color=red>sqlserver介绍<br><img src=\"cid:001\" border=\"1\"><br>详情参考附件</font>","html","utf-8")

# 创建一个MIMEText对象,附加sqlserver.txt文档
msg_attach = MIMEText(open("doc/sqlserver.txt", "rb").read(),"base64","utf-8")

# 指定文件格式类型
msg_attach["Content-Type"] = "application/octet-stream"

# 指定Content-Disposition值为attachment则出现下载保存对话框,保存的默认文件名使用filename指定
msg_attach["Content-Disposition"] = "attachment; filename=\"sqlserver.txt\""

# MIMEMultipart对象附加text,img,attach内容
msg_multipart.attach(msg_text)
msg_multipart.attach(addimg("img/001.png","001")) # 图片路径与标签,001对应上方html中的<img src="cid:001">
msg_multipart.attach(msg_attach)

# 发件人
msg_multipart['From'] = formataddr([from_name, from_addr])
# 邮件标题
msg_multipart['Subject'] = my_title

# SMTP服务器地址
smtp_srv = "smtp.qq.com"

try:

    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)

    # 使用授权码登录QQ邮箱
    srv.login(from_addr, from_pwd)

    # 使用sendmail方法来发送邮件
    srv.sendmail(from_addr, [to_addr], msg_multipart.as_string())
    print('发送成功')
except Exception as e:
    print('发送失败')
    # 打印具体报错
    print(e)
finally:
    # 无论发送成功还是失败都要退出你的QQ邮箱
    srv.quit()

运行结果如图

参考

《python自动化运维技术与最佳实践》

https://docs.python.org/2.7/library/smtplib.html

https://docs.python.org/2.7/library/email.mime.html

用python发送qq邮件_fgdwa的博客-CSDN博客_python发送qq邮件

python发送QQ邮件_齐天大圣的博客-CSDN博客_python 发送qq邮件

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐