我想使用 Python 的 smtplib 发送带有 Python 脚本的电子邮件。
如果可以建立与服务器的加密连接,脚本应该只发送电子邮件。要加密与端口 587 的连接,我想使用 STARTTLS。
使用一些示例,我编写了以下代码:
smtp_server = smtplib.SMTP(host, port=port)
context = ssl.create_default_context()
smtp_server.starttls(context)
smtp_server.login(user, password)
smtp_server.send_message(msg)
msg、主机、端口、用户、密码是我脚本中的变量。我有两个问题:
- 连接是始终加密还是容易受到 STRIPTLS 攻击(https://en.wikipedia.org/wiki/STARTTLS)。
- 我应该使用 SMTP 对象的 ehlo() 方法吗?在某些示例中,它在调用 starttls() 之前和之后显式调用。另一方面,在 smptlib 的文档中,如果有必要,sendmail() 将调用它。
[编辑]
@tintin 解释说,这ssl.create_default_context()
可能会导致不安全的连接。因此,我通过以下方式使用一些示例更改了代码:
_DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
'!eNULL:!MD5')
smtp_server = smtplib.SMTP(host, port=port)
# only TLSv1 or higher
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.options |= ssl.OP_NO_SSLv2
context.options |= ssl.OP_NO_SSLv3
context.set_ciphers(_DEFAULT_CIPHERS)
context.set_default_verify_paths()
context.verify_mode = ssl.CERT_REQUIRED
if smtp_server.starttls(context=context)[0] != 220:
return False # cancel if connection is not encrypted
smtp_server.login(user, password)
对于密码设置,我使用了一些最新版本的代码ssl.create_default_context()
。这些设置合适吗?
注意:在我原来的问题的代码中是一个错误。这是相关行的正确版本:
smtp_server.starttls(context=context)
[\编辑]