smtplib.SMTP starttls 因 tlsv1 警报解码错误而失败

Posted

技术标签:

【中文标题】smtplib.SMTP starttls 因 tlsv1 警报解码错误而失败【英文标题】:smtplib.SMTP starttls fails with tlsv1 alert decode error 【发布时间】:2014-06-30 06:35:03 【问题描述】:

我今天遇到了以下奇怪的行为。

以下代码适用于 Python 3.3:

smtp = smtplib.SMTP()
smtp.connect(host="smtp.gmail.com", port=587)
smtp.ehlo()
smtp.starttls()

在 Python 3.4 中,上述代码不起作用,而是遇到以下错误:

   File "smtp_test.py", line 10, in <module>
    smtp.starttls()
   File "/usr/lib/python3.4/smtplib.py", line 676, in starttls
    server_hostname=server_hostname)
   File "/usr/lib/python3.4/ssl.py", line 344, in wrap_socket
    _context=self)
   File "/usr/lib/python3.4/ssl.py", line 540, in __init__
    self.do_handshake()
   File "/usr/lib/python3.4/ssl.py", line 767, in do_handshake
    self._sslobj.do_handshake()
   ssl.SSLError: [SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:598)

如果将上面的代码修改为在构造函数中指定主机和端口,而不使用connect方法,如下面的代码,那么它可以工作。

smtp = smtplib.SMTP(host="smtp.gmail.com", port=587)
smtp.ehlo()
smtp.starttls()

上述行为发生在 OpenSSL 版本 1.0.1f 和 OpenSSL 1.0.1g

有人可以向我解释这种行为吗?

【问题讨论】:

【参考方案1】:

根据 tcpdump,3.4 中的代码以空目标名称发送 SNI 扩展。 SNI(服务器名称指示)在同一 IP 地址后面有不同证书时使用。我认为这是一个错误:如果它没有名称,则不应发送 SNI 扩展,而是发送其中包含零长度名称的扩展。

【讨论】:

为什么第二段代码,在构造函数中使用相同的连接方法,然后工作? 因为它可能将主机保存在构造函数中并将其重用于 SNI 扩展。并且连接可能不会保存主机。

以上是关于smtplib.SMTP starttls 因 tlsv1 警报解码错误而失败的主要内容,如果未能解决你的问题,请参考以下文章

为什么发送电子邮件时不显示消息? - smtplib - Python

使用python发送邮件会出错

如何使用 Python 发送邮件

Python Ethical Hacking - Malware Analysis

通过yandex账户发送邮件的python脚本是啥?

多部分电子邮件 PDF 附件空白