使用 Python 调用邮件服务器发送邮件, 使用的协议是 SMTP(Simple Mail Transfer Protocol), 下图为使用 TCP/IP 基于 SMTP 发送邮件的过程示意图:
SMTP 协议工作原理:
SMTP 工作在两种情况下: 一是电子邮件从用户端传输到服务器: 二是从某一个 MTA(Message Transfer Agent) 传输到另一个 MTA.SMTP 也是请求 / 响应协议, 命令和响应都是基于 NVT ASCII 文本, 并以 CR 和 LF 符结束. 响应包括一个表示返回状态的三位数字代码. SMTP 在 TCP 协议 25 号端口监听连续请求.
SMTP 连接和发送过程
(1) 建立 TCP 连接.
(2) 客户端发送 HELO 命令以标识发件人自己的身份, 然后客户通过发送 MIAL 命令标识出电子邮件的发起人; 服务器端正希望以 OK 作为响应, 表明准备接收.
(3) 客户端发送 RCPT 命令, 以标识该电子邮件的计划接收人, 可以有多个 RCPT 行; 服务器端则表示是否愿意为收件人接收邮件.
(4) 协商结束, 发送邮件, 用命令 DATA 发送.
(5) 以 "." 号表示结束输入内容一起发送出去, 结束此次发送, 用 QUIT 命令退出.
Python 使用 SMTP 发送邮件
在 python 中, 发送邮件主要包括 email 和 smtplib, 其中 email 实现邮件构造, smtplib 实现邮件发送. 在 smtplib 库中, 主要主要用 smtplib.SMTP() 类, 用于连接 SMTP 服务器, 发送邮件. SMTP 类中常用方法如
方法 | 描述 |
SMTP.set_debuglevel(level) | 设置输出 debug 调试信息,默认不输出 |
SMTP.docmd(cmd[, argstring]) | 发送一个命令到 SMTP 服务器 |
SMTP.connect([host[, port]]) | 连接到指定的 SMTP 服务器 |
SMTP.helo([hostname]) | 使用 helo 指令向 SMTP 服务器确认你的身份 |
SMTP.ehlo(hostname) | 使用 ehlo 指令像 ESMTP(SMTP 扩展)确认你的身份 |
SMTP.ehlo_or_helo_if_needed() | 如果在以前的会话连接中没有提供 ehlo 或者 helo 指令,这个方法会调用 ehlo() 或 helo() |
SMTP.has_extn(name) | 判断指定名称是否在 SMTP 服务器上 |
SMTP.verify(address) | 判断邮件地址是否在 SMTP 服务器上 |
SMTP.starttls([keyfile[, certfile]]) | 使 SMTP 连接运行在 TLS 模式,所有的 SMTP 指令都会被加密 |
SMTP.login(user, password) | 登录 SMTP 服务器 |
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) | 发送邮件 from_addr:邮件发件人 to_addrs:邮件收件人 msg:发送消息 |
SMTP.quit() | 关闭 SMTP 会话 |
SMTP.close() | 关闭 SMTP 服务器连接 |
python 中通过 SMTP 发送邮件主要包括以下几个步骤 (以 qq 邮箱为例):
1. 开通邮箱 SMTP 服务, 获取邮箱授权码, 邮箱 SMTP 开通路径: 邮箱设置 / 账户 / POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务
2. 编辑邮件内容, 主要包括三部分内容: 信封, 首部和正文; 其中信封包括发送邮箱, 接收邮箱等;
3. 初始化配置信息, 调用 SMTP 发送邮件
代码实现如下所示, 其中 python 版本为 3.7:
- import smtplib
- import email.utils
- from email.mime.text import MIMEText
- class Msg():
- def __init__(self):
- pass
- @staticmethod
- def creat_msg():
- # Creat mail information
- msg = MIMEText('Come on', 'plain', 'utf-8')
- msg['From'] = email.utils.formataddr(('Author', 'xxxxxxxxxx@qq.com'))
- msg['To'] = email.utils.formataddr(('Recipient', 'xxxxxxxxx@163.com'))
- msg['Subject'] = email.utils.formataddr(('Subject', 'Good good study, day day up!'))
- return msg
- class EmailServer():
- def __init__(self):
- pass
- @staticmethod
- def config_server():
- # Configure mailbox
- config = dict()
- config['send_email']= 'xxxxxxxxxx@qq.com'
- config['passwd'] = 'xxxxxxxxxx'
- config['smtp_server'] = 'smtp.qq.com'
- config['target_email'] = 'xxxxxxxxxx@163.com'
- return config
- def send_email(self):
- # Use smtp to send email to the target mailbox
- msg = Msg.creat_msg()
- config = self.config_server()
- server = smtplib.SMTP()
- server.connect(host=config['smtp_server'], port=25)
- server.login(user=config['send_email'], password=config['passwd'])
- server.set_debuglevel(True)
- try:
- server.sendmail(config['send_email'],
- [config['target_email']],
- msg.as_string())
- finally:
- server.quit()
- if __name__ == '__main__':
- emailServer = EmailServer()
- emailServer.send_email()
发送邮件过程跟踪如下:
经过测试, 从 QQ 邮箱向 163 邮箱可正常发送邮件, 从 163 邮箱发送到 QQ 邮箱则会进入垃圾箱, 翻阅了不少资料, 目前还没有解决如何摆脱垃圾箱的困扰, 如有知道的朋友, 可在评论区解惑, 不甚感谢~
参考文献:
(1) https://blog.51cto.com/lizhenliang/1875330
(2)TCP/IP 详解卷 1: 协议
来源: https://www.cnblogs.com/Summerhack/p/11387799.html