Python SMTP 库无法处理 IPv6

Python SMTP library can't handle IPv6

请问如何在 SMTP 库中添加 IPv6 选项?

当我尝试使用 IPv6 连接到 SMTP 时出现此错误:

 smtpserver = smtplib.SMTP("smtp.gmail.com", 587, source_address=('2a00:xxxx:5::1e7', 80, 0, 0))

错误:TypeError: AF_INET address must be a pair (host, port)

这意味着 smtplib.py 不支持 IPv6

我找到了一篇关于“https://bugs.python.org/issue3461”的文章。我试图将补丁添加到我的 smtplib.py 但它没有用

谁能帮我做这个?

... source_address=('2a00:xxxx:5::1e7', 80, ...

错误消息具有误导性。在 Linux 上执行 strace 表明它实际上尝试绑定到给定的 IP 和端口但失败了 - 然后发出此误导性错误消息。它失败的原因可能有多种,但典型的情况可能是它没有竞标端口的权限(这里绑定到端口 80 需要 root 权限)或者该端口已被另一个套接字使用(端口 80 是通常用于网络服务器)。

一般来说,最好只指定 IP 地址并将端口保留为 0。这样它将使用给定的 IP 地址作为源 IP,但会选择一个随机(临时)端口作为源端口。

I found an article about that "https://bugs.python.org/issue3461"

这是无关的。它仅与 SMTP 对话期间 EHLO 命令中显示的发件人有关。如果这是一个问题,只需给出与 local_hostname 参数一起使用的值。

Python 3的socket.create_connection获得目标地址的第一个DNS解析条目是可连接的(这是一个行为,在Python中记录为DNS设计不稳定).

https://github.com/python/cpython/blob/fdcb675e/Lib/socket.py#L824

CPython 实现 _socket.connect 在创建时发现套接字的地址族与其他时间的地址族不匹配时抛出有问题的错误,

https://github.com/python/cpython/blob/1aa6be0/Modules/socketmodule.c#L1807

仔细观察 socket.create_connection,我猜 source_address 参数无法控制用于目标的地址族。套接字对象 sockcreate_connection 中使用已解析目标地址的地址族创建。然后 source_address 用于通过调用 sock.bind(source_address) 来指定对象的源。似乎在这一点上,如果解析的目标是 IPv4 但 source_address 是 IPv6,则会抛出错误?

作为一个可能的修复,它不会 monkey-patch socket.create_connection,我可以想象调用者不是在目标地址中提供符号主机名,而是首先将主机名解析为 AAAAA 条目,具体取决于所需的系列。调用者提供数字记录作为目标地址。源地址的族也应该与所需的族一致。

换句话说,调用者可以使用socket.getaddrinfo来找到所需的家庭所需的目标地址。 request 库的用户等其他调用者可以 hot-wire socket.create_connection 以相同的想法。

https://docs.python.org/3/library/socket.html#socket.getaddrinfo