DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Python SMTP 报 WRONG_VERSION_NUMBER:核对端口与 TLS 启动方式

Python SMTP 连接报 WRONG_VERSION_NUMBER,按服务实际入口选择 SMTP 加 STARTTLS 或 SMTP_SSL,区分超时、握手和认证,并保留证书验证。

Python 用 SMTP_SSL 连接邮件服务的 587 端口,建立连接时出现 ssl.SSLError: [SSL: WRONG_VERSION_NUMBER];改成 465 又超时。先核对服务商为这个主机提供的端口和 TLS 方式。报错里的“版本”并不直接证明需要降低 TLS 版本,客户端在错误阶段发起握手,也可能收到无法按 TLS 解析的响应。

以下针对 Python 3 的 smtplib。示例按当前 Python 3.x API 编写,仅演示连接与 TLS,不包含登录或发送邮件。邮件平台实际支持的入口、账号认证方式和策略,应以当前配置为准。

SMTP_SSL 从连接开始就使用 TLS

SMTP_SSL 适用于建立 TCP 连接后立即 TLS 握手的入口,通常称为隐式 TLS。465 是这类邮件提交服务的标准端口,但不能据此推断任意主机都提供 465 服务。

STARTTLS 入口先进行 SMTP 协议交互,再通过 STARTTLS 命令升级为 TLS。587 常用于这种提交方式。若把 SMTP_SSL 接到一个等待 SMTP 交互的入口,两端对连接开头的数据理解不同,就可能在握手时失败。

端口数字只是线索。自建服务、端口映射或代理可以采用不同入口,需要一起核对目标主机、端口、实际后端服务及加密方式。若服务商只提供某一种入口,不能靠换客户端端口让另一种入口自动出现。

STARTTLS 应在 SMTP 对象上调用

服务确认提供 STARTTLS 时,连接结构应类似下面这样。主机和端口需要替换为真实配置,不能直接运行示例域名:

import smtplib
import ssl

context = ssl.create_default_context()

with smtplib.SMTP("smtp.example.com", 587, timeout=15) as smtp:
    smtp.ehlo()
    smtp.starttls(context=context)
    smtp.ehlo()

with 管理的是 SMTP 连接对象。不要改成 with smtp.starttls(...) as smtp::starttls() 返回协议响应元组,不会返回新的连接管理器,这种写法可能报 AttributeError: __enter__ 或其他上下文管理协议错误。

升级完成后再次 ehlo(),用于重新获取加密连接中的服务能力。上面的默认 SSL context 保留证书与主机名验证;若使用自有 CA,需要在保留验证的前提下配置相应信任材料。

服务器没有提供 STARTTLS,或升级被拒绝时,应停止这条连接并检查入口配置。不要捕获异常后继续以明文登录,也不要把关闭证书校验作为普通修复。

隐式 TLS 入口才使用 SMTP_SSL

若实际服务明确要求连接开始就使用 TLS,可以采用下面的结构,同样只演示连接:

import smtplib
import ssl

context = ssl.create_default_context()

with smtplib.SMTP_SSL("smtp.example.com", 465, timeout=15,
                      context=context) as smtp:
    smtp.ehlo()

这里不再调用 starttls()。两段示例是按服务配置选择的不同连接方式,不能在失败时无条件轮流尝试,更不能在两者都失败后降级为明文发送账号信息。

按异常发生阶段继续排查

连接超时或拒绝,先检查主机解析、网络路径、访问策略和服务是否监听。465 超时只能说明这条连接没有按预期完成,不能证明 STARTTLS 代码一定有问题。

已经进入 TLS 握手,却报 WRONG_VERSION_NUMBER,继续核对是否连到了明文服务、错误端口或不符合预期的代理入口。若端口和启动方式都正确,仍需保留完整异常及服务日志,调查实际协议协商;单个错误字符串不足以确定所有根因。

出现证书验证错误时,检查证书身份、有效期和信任链,而不是换成不验证的 context。TLS 已完成后才出现 SMTPAuthenticationError,则转向当前账号权限、允许的认证方式和平台策略。握手方式正确,不保证旧的用户名密码登录仍受平台支持。

记录诊断信息时,保留阶段、主机、端口和异常类型即可。开启完整 SMTP 调试可能记录协议内容,应避免把账号、认证数据、收件人和邮件正文直接带入共享日志。

验收应覆盖加密和原有发送流程

先在不发送邮件的受控连接中确认选定入口完成 TLS,证书身份验证通过,并能获取升级后的服务能力。随后按平台当前支持的认证方式和原有业务流程做受控发送,核对是否只发送一次,以及收信端实际结果。

变更前保存旧配置和代码,只调整已确认的连接方式与端口。异常后不要无条件重试整笔发送:若邮件已被服务器接受,断线后的重复提交可能产生重复邮件。回退代码不能撤回已经发送的邮件,应先依据发送记录确定需要补发的范围。