使用Python smtplib发送不包含密钥文件(仅包含证书文件)的电子邮件
问题内容:
尝试使用以下脚本发送带有证书文件的电子邮件:
import smtplib
client = smtplib.SMTP(myhost, myport)
client.ehlo()
client.starttls(certfile=mycertfile)
client.ehlo()
client.login(myusername, mypassword)
client.sendmail(sender, receiver, Message)
client.quit()
我收到以下错误:
SSLError: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
我认为文档(smtplib.html和ssl.html)说我需要提供一个私钥。我只有证书文件(base64
PEM格式)。我的开发人员说,在这种情况下不需要私钥,因为我不需要标识连接的本地端。
题
是否可以在不提供私钥的情况下发送电子邮件?如果需要私钥,为什么?
问题答案:
有两种使用SSL /
TLS的方法:客户端身份验证和“基本”,即客户端未经身份验证。在客户端身份验证的连接中,服务器和客户端都向对方发送证书。在“基本”中,只有服务器可以。
如果您既未通过证书也未通过密钥文件,smtplib
则将使用对客户端进行身份验证的基本连接。
如果您使用证书,它将用于客户端验证的连接。在这种情况下,服务器将通过签名握手消息来要求客户端显示其拥有证书。为了使客户端能够做到这一点,它还需要私钥,该私钥可以在证书文件中,也可以作为单独的密钥文件。
长话短说,如果要使用客户端证书,则还必须使用密钥。如果没有,您可以将两者都留空。
OTOH,也许您有要用于连接的服务器证书文件或CA列表?
在这种情况下,你需要将它传递给ssl.wrap_socket
在ca_certs
参数。由于您使用Python
2.6有没有简单的方法来做到这一点与smtplib
(Python的3.3+有一个context
参数STARTTLS)。
如何解决这个问题取决于您的应用程序。例如,如果您不需要ssl
其他任何东西,那么骇人听闻的解决方案就是用猴子补丁ssl.wrap_socket
来提供您的ca_cert
(以及cert_reqs=CERT_REQUIRED
可能的)补丁。
一个更完善的解决方案是smtplib.SMTP
使用您自己的变体进行扩展,该变体允许传入这些参数。