Python使用SMTP协议实现邮件发送(含明文/SSL加密/TLS加密)

SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。
Python对SMTP支持有smtplibemail两个模块

  1. email负责构造邮件
  2. smtplib负责发送邮件

Tips

欲看完整代码请见我的GitHub.

一、基本环境设置

以下笔者测试使用163邮箱给foxmail邮箱发邮件,所以需要手动对发送方邮箱配置SMTP协议,其余邮箱操作同理。
首先,登录到163邮箱,然后在设置菜单中点击如下选项。
在这里插入图片描述
然后,手动开启SMTP服务,此时可能需要设置客户端授权码,即为登录第三方邮件客户端的专用口令,和该邮箱登录密码不同,对于163邮箱可以自己设置授权码,但如果是QQ或者foxmail邮箱会有系统自动分配给用户授权码。
111
因为发送方是163邮箱,所以此时用到的SMTP服务器是smtp.163.com,在163邮箱设置可看到如下图所示:
在这里插入图片描述
对于其他邮箱相应的SMTP服务器是smtp.xxx.com,比如以下是常用邮箱SMTP端口及登录说明(亲测可用):

邮箱SMTP服务器登录口令支持加密方式对应端口号
163smtp.163.com个人设置授权码明文/SSL加密25/465
126smtp.126.com个人设置授权码明文/SSL加密25/465
QQsmtp.qq.com系统分配授权码明文/SSL加密/TLS加密25/465/587
Gmailsmtp.gmail.com邮箱登录密码TLS加密587

二、实现文本邮件发送

我们以下先来实现一下简单的文本邮件的发送代码。其中plain表示纯文本内容。

msg = MIMEText('I Love You','plain','utf-8')
from email.mime.text import MIMEText
from email.utils import formataddr
import smtplib
# SMTP服务器以及相关配置信息
smtp_sever = 'smtp.163.com'
from_addr = 'xxx@163.com'
password = 'xxxx'  # 授权码
to_addr = 'xxx@foxmail.com'

# 1.创建邮件(写好邮件内容、发送人、收件人和标题等)
msg = MIMEText('I Love You','plain','utf-8')
msg['From'] = formataddr(('若水',from_addr)) # 发件人昵称和邮箱
msg['To'] = formataddr(('小伙伴',to_addr)) # 收件人昵称和邮箱
msg['Subject'] = '2019你好'               # 邮件标题
# 2.登录账号
sever = smtplib.SMTP(smtp_sever,25) # 明文传输端口号是25
sever.login(from_addr,password)
# 3.发送邮件
sever.sendmail(from_addr,to_addr,msg.as_string())
sever.quit()

【注意事项】:
1)上面代码中发送方是163邮箱,所以密码不是邮箱的登录密码,而是手动开启SMTP协议后设置或分配的授权码,但如果是Gmail则使用的密码是登录密码
2)如果没有加入如下代码,则会被识别为垃圾邮件,故出现错误代码是554smtplib.SMTPDataError错误。点击查看邮件退信代码说明

msg['From'] = formataddr(('若水',from_addr))
msg['To'] = formataddr(('小伙伴',to_addr))
msg['Subject'] = '2019你好'

在这里插入图片描述
3)如果是群发邮件,则需要发送到多个邮箱,则sever.sendmail中的to_addr可以是存储多个邮箱的列表。
4)msg['To']接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可
5)以上代码最好在本机的IDE(如Pytharm)中运行,笔者同样在Pycharm运行成功的邮件发送代码,在Jupyter中运行却屡屡报SMTPDataError错,如有大佬知道原因还请不吝赐教。

若一切顺利,则可在QQ邮箱上看到该邮件(往往在垃圾箱中)
在这里插入图片描述

三、发送HTML邮件

只需要把上面发送纯文本代码中的MIMEText中的plain换成html即可,然后再把html文本粘贴在前面,代码如下:

msg = MIMEText('<html><body>'
               '<h1>2019请关注我的博客</h1>'
               '<p>我的博客地址是:'
               '<a href="https://blog.csdn.net/sl_world">sl_world</a>...'
               '</p></body></html>','html','utf-8')

运行成功可以在收件箱看到如下图:
在这里插入图片描述

四、发送带附件的邮件

如果我们想要发送带附件的邮件,先来分析一下带附件邮件的组成,很容易得到

  • 邮件内容=邮件正文+邮件附件

所以此处我们可以使用MIMEMultipart创建实例,然后通过把邮件正文邮件附件分别添加(attach)到里面即可,因为MIMEBase可以表示任何对象,所以此处使用它存储邮件附件。此处我使用的附件路径是/home/sparkfly/Desktop/测试文档.doc

  • MIMEMultipart
    • MIMEText-邮件正文
    • MIMEBase-邮件附件

代码如下:

from email import encoders
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.utils import formataddr
import smtplib
# SMTP服务器以及相关配置信息
smtp_sever = 'smtp.163.com'
from_addr = 'xxx@163.com'
password = 'xxx'  # 授权码
to_addr = 'xxx@foxmail.com'
# 创建MIMEMultipart实例,通过attach方法把MIMEText和MIMEBase添加进去
msg = MIMEMultipart()
msg['From'] = formataddr(('若水',from_addr))
msg['To'] = formataddr(('小伙伴',to_addr))
msg['Subject'] = 'Welcome to 2019'
# 添加邮件正文MIMEText
msg.attach(MIMEText('附件如下','plain','utf-8'))
# 添加附件就是加上一个MIMEBase,从本地读取一个word文档
with open('/home/sparkfly/Desktop/测试文档.doc','rb') as f:
    # 设置附件的MIME和文件名,这里是docx类型
    mimebase = MIMEBase('我的测试文档','docx')
    # 加上必要的头信息
    mimebase.add_header('Content-Disposition', 'attachment', filename='myDocument.docx')
    mimebase.add_header('Content-ID', '<0>')
    mimebase.add_header('X-Attachment-Id', '0')
    # 把附件的内容读进来
    mimebase.set_payload(f.read())
    # 用Base64编码
    encoders.encode_base64(mimebase)
    # 添加到MIMEMultipart中
    msg.attach(mimebase)

server = smtplib.SMTP(smtp_sever,25)
server.set_debuglevel(1)  # 查看实时登录日志信息
server.login(from_addr,password)
server.sendmail(from_addr,to_addr,msg.as_string())
server.quit()

其中server.set_debuglevel(1)可以查看实时登录日志信息,方便debug。
运行结果如下,OK!
在这里插入图片描述

五、将图片嵌入到邮件正文

【方法一】:

首先还是和上一步一样,把图片当做附件添加到MIMEMultipart实例中,然后在MIMEText中把plain改成html,使用<img>html单标签和属性src="cid:Image"把附件中的图片引入到邮件正文中,若有多个图片,给它们依次编号,然后引用不同的cid:x即可。此处代码仅在上一步中修改读取本地图片的文件路径等相关信息和如下代码即可。

msg.attach(MIMEText('<html><body><h1>2019请关注我的博客</h1>'
                    '<p><img src="cid:Image"></p>'
                    '</body></html>','html','utf-8'))

并且修改Content-ID参数对应为Image

mimebase.add_header('Content-ID', 'Image')
【方法二】:

在方法一的基础上,直接使用MIMEImage对象处理图片文件,替换MIMEBase对象,仅三行代码ok。
修改部分代码如下:

from email.mime.image import MIMEImage
...
with open('/home/sparkfly/Desktop/image.png','rb') as f:
    mimeImage = MIMEImage(f.read())
    mimeImage.add_header('Content-ID', 'Image')
    msg.attach(mimeImage)
...

成功后收到邮件如下:
在这里插入图片描述

六、额外补充

1.同时支持纯文本和HTML格式邮件查看

对于查看不了HTML格式邮件的情况,我们可以同时编写一份纯文本plain格式的内容,然后给收件人可选去读取。
还是以上面的的代码为例子,此处在加入邮件正文MIMEText的时候,加入两次,一次是html格式的,一次是plain纯文本格式的。之后在MIMEMultipart中加入alternative参数表示二选一。修改部分代码如下:

msg = MIMEMultipart('alternative')
msg.attach(MIMEText('2019请关注我的博客', 'plain', 'utf-8'))
msg.attach(MIMEText('<html><body><h1>2019请关注我的博客</h1>'
                    '<p><img src="cid:0"></p>'
                    '</body></html>','html','utf-8'))

成功后收到邮件如下:
在这里插入图片描述
点击纯文本显示如下:
在这里插入图片描述

2.常用邮箱SMTP加密方式

使用上述SMTP协议发送邮件实则发送的是明文邮件,如果想要加密,有如下几种方式。
1)明文传输: 端口号是25

server = smtplib.SMTP(smtp_sever,25)

2)SSL加密: 端口号是465,通信过程加密,邮件数据安全。

server = smtplib.SMTP_SSL(smtp_sever,465)

3)TLS加密: 端口号是587,通信过程加密,邮件数据安全,使用正常的smtp端口。对于TLS加密方式需要先建立SSL连接,然后再发送邮件。此处使用starttls()来建立安全连接

server = smtplib.SMTP(smtp_sever,587)
server.starttls()

不同邮箱支持不同的加密协议,常用邮箱支持的加密方式和对应端口号如下:

邮箱SMTP服务器端口号支持加密方式
163smtp.163.com25/465明文/SSL加密
126smtp.126.com25/465明文/SSL加密
QQsmtp.qq.com25/465/587明文/SSL加密/TLS加密
Gmailsmtp.gmail.com587TLS加密
3.登录gmail常见问题

笔者以上都用的是163邮箱作为发送方,如果使用gmail作为发送方,除了SMTP服务器要改成smtp.gmail.com外,还需要把端口改成587,密码直接使用gmail的登录密码即可。但依然可能会登录失败。原因是目前gmail对安全性较低的应用的访问权限进行控制,我们需要手动设置。点击进行Gmail安全性较低的应用的访问权限设置,点击界面如下,设置启用即可。
在这里插入图片描述

参考文献:
[1]廖雪峰.SMTP发送邮件
[2]Python之简单的SMTP发送邮件详细教程附代码
[3]Google账号帮助
[4]Python中发邮件(明文/SSL/TLS三种方式)

  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Netty是一款高性能的网络应用框架,支持SSL/TLS加密来保护网络通信的安全性。SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是网络通信中广泛使用加密协议,用于在客户端和服务器之间建立安全的通信信道。 Netty提供了一些组件和类来实现SSL/TLS加密。首先,我们需要使用javax.net.ssl包中的类来创建SSLContext对象。SSLContext是SSL/TLS协议的入口点,它包用于加密和解密数据的加密算法和密钥。我们需要为SSLContext对象配置密钥库和信任库,密钥库用于存储证书和私钥,而信任库用于存储可信的证书。 接下来,我们需要创建SslHandler对象,将其添加到Netty的ChannelPipeline中。SslHandler作为一个ChannelHandler,负责处理SSL/TLS握手过程和数据的加密解密。当建立连接时,SslHandler会自动执行握手过程,包括协商加密算法、验证证书以及生成会话密钥等。 一旦握手完成,SslHandler会将数据加密发送到网络,并将接收到的密解密成。这样可以确保在网络传输过程中的数据保密性和完整性。此外,SslHandler还提供了一些方法来获取会话信息,如远程主机的证书和协商的加密算法。 使用Netty的SSL/TLS加密功能能够有效地提高网络通信的安全性。通过配置SSLContext和添加SslHandler,我们可以方便地实现对网络通信的加密和解密。无论是在客户端还是服务器端,都可以使用Netty的SSL/TLS加密功能来保护数据的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SL_World

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值