【问题标题】:How to accept self-signed certificate from e-mail server via smtplib (TSL)?如何通过 smtplib (TLS) 接受来自电子邮件服务器的自签名证书?
【发布时间】:2019-07-25 08:11:08
【问题描述】:

我的脚本

from stmplib import SMTP
con = SMTP(server, port)
con.starttls()
con.login(user, pass)
con.quit()

出现错误: python2.7/ssl.py", line 847, in do_handshake self._sslobj.do_handshake()

当我对该服务器运行命令 openssl 时,它会出现错误 21:Verify return code: 21 (unable to verify the first certificate)

我想知道如何在 python 选项的 smtplib 中指定“通过 tls 建立连接到电子邮件服务器时始终接受自签名证书”? 就像我在requests.get 设置键verify=False 中所做的那样。

更新 此带有自定义 smtp 类和 context = ssl._create_unverified_context() 的变体返回与上述相同的错误:

import smtplib
import ssl

class MySMTP(smtplib.SMTP):
    def __init__(self, host='', port=0, timeout=5):
        smtplib.SMTP.__init__(self, host, port, timeout=timeout)
        self._host = host

    def starttls(self, keyfile=None, certfile=None, context=None):
        from urllib import _have_ssl

        self.ehlo_or_helo_if_needed()
        if not self.has_extn("starttls"):
            raise SMTPNotSupportedError("STARTTLS extension not supported by server.")
        (resp, reply) = self.docmd("STARTTLS")
        if resp == 220:
            if not _have_ssl:
                raise RuntimeError("No SSL support included in this Python")
            if context is not None and keyfile is not None:
                raise ValueError("context and keyfile arguments are mutually "
                             "exclusive")
            if context is not None and certfile is not None:
                raise ValueError("context and certfile arguments are mutually "
                             "exclusive")
            if context is None:
                context = ssl._create_stdlib_context(certfile=certfile,
                                                 keyfile=keyfile)
            self.sock = context.wrap_socket(self.sock,
                                        server_hostname=self._host)
            self.file = None
            # RFC 3207:
            # The client MUST discard any knowledge obtained from
            # the server, such as the list of SMTP service extensions,
            # which was not obtained from the TLS negotiation itself.
            self.helo_resp = None
            self.ehlo_resp = None
            self.esmtp_features = {}
            self.does_esmtp = 0
        return (resp, reply)

con= MySMTP(server, port)
context  = ssl._create_unverified_context()
con.starttls(context = context)
con.login(user, pass)
con.quit()

【问题讨论】:

  • 您使用的是哪个版本的 Python?
  • 问题状态 2.7
  • 您的自签名证书是否来自 CA(“认证机构”)?
  • 您是否尝试过使用ssl._https_verify_certificates(enable=False)? (尽管这不应该影响这种情况)。对于第二个变体,请尝试context = ssl._create_unverified_context(cert_reqs=ssl.CERT_NONE)(或在创建上下文后手动执行相同的操作:context.verify_mode = ssl.CERT_NONE)。
  • 感谢尝试,但都失败了。

标签: python python-2.7 ssl smtplib starttls


【解决方案1】:

看起来你的方法是继承 SMTP 类并覆盖 starttls() 方法以接受 context 参数是可行的方法 - 它实际上甚至在 Python 3.x 中引入。

但是:

con = MySMTP(server, port)
context  = ssl.create_default_context(cafile=PATH_TO_CERTIFICATE_AUTHORITY_ROOT_CRT_FILE)
con.starttls(context=context)
con.login(user, pass)
con.quit()

应该可以代替未经验证的上下文。

当您对证书进行自签名时,您使用了自己的证书颁发机构,因此您之前可能创建了根 CA 证书。

您的 SMTP 客户端必须知道此根证书,才能验证您的 SMTP 服务器证书。
因此,找到该文件,将其放在您的 SMTP 客户端可访问的位置,并将此路径设置为值PATH_TO_CERTIFICATE_AUTHORITY_ROOT_CRT_FILE

你所做的是:

ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile)

certfilekeyfile 是客户端证书和密钥 - 某些服务器不会接受来自未经验证的客户端的连接。

有用的链接:
ssl.create_default_context() documentation
In case you can't find your root certificate you can start from scratch(只需忽略图片上的所有 MacOS 窗口 - 您的 SMTP 客户端想要访问根证书文件 - 他们在本指南中添加到浏览器的那个文件)

【讨论】:

    【解决方案2】:

    迟到的答案,但我使用ssl._create_unverified_context()ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852) 固定在python 3.7 上,即:

    import smtplib, ssl
    context = ssl._create_unverified_context()
    with smtplib.SMTP_SSL("domain.tld", 465, context=context) as server:
        server.login(user, password)
        server.sendmail(sender_email, receiver_email, message.as_string())
    

    【讨论】:

    • 你很幸运。我很早就尝试过这种方法,但没有帮助。
    • 谢谢,成功了!即使我不得不在“smtp.gmail.com”上使用它
    猜你喜欢
    • 2013-12-18
    • 2012-03-17
    • 2019-12-23
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 2012-08-23
    • 2019-05-13
    相关资源
    最近更新 更多