Python 使用本地 SMTP 服务器在 docker 容器内发送邮件
Python send mail inside docker container with local SMTP server
我想用 python 上的 smtp
库发送邮件。我知道它在端口号 25 上使用本地 smtp 服务。我有以下代码。这些代码 运行 在我的本地没有任何问题,邮件发送成功。但是当我将它们移动到 docker 容器时,邮件不会发送,也不会给出任何错误。
我的代码:
from_mail = 'noreply@testmail.com'
to_mail = 'to@testmail.com'
s = smtplib.SMTP('localhost')
subject = 'Test Subject'
content = 'content test'
message = f"""\
Subject: {subject}
To: {to_mail}
From: {from_mail}
{content}"""
result = s.sendmail(from_mail, to_mail, message)
s.quit()
在 运行 执行这些代码后,我得到空字典 ({}) 作为 result
值。在sendmail方法描述中有这样的:
... the message was accepted for delivery to three
of the four addresses, and one was rejected, with the error code
550. If all addresses are accepted, then the method will return an
empty dictionary.
是关于网络配置的吗?我应该配置任何网络设置吗?
默认情况下,docker 容器 运行 在单独的网络堆栈中,因此 localhost
与 docker 容器内的含义不同您的代码 运行 直接在您的计算机上。
根据您的 SMTP 服务器的设置方式,它也可能被配置为拒绝发送任何电子邮件,但那些直接来自您的计算机的电子邮件,并且 docker 容器可能被视为不应该发送的外来者通过它发送电子邮件。
我想最简单的解决方案是 运行 您的 docker 容器 --net=host
。有了这个,docker 容器的网络堆栈将与您计算机的堆栈相同,一切都应该像代码 运行ning 直接在 docker.[=12= 之外一样工作。 ]
如果它在主机上运行,请尝试使用主机 IP 而不是 localhost
。
s = smtplib.SMTP(HOST_IP)
或者按照 Arthur 的建议,您可以使用 --net=host
运行 主机网络中的容器,然后继续使用 localhost
。
您共享的代码是 SMTP 客户端应用程序。假设使用 SMTP 客户端标准库 smtplib
并且 SMTP 服务器在本地主机上 运行ning,代码将在以下条件下在 Docker 容器中运行:
- 您使用
--net=host
启动容器,则无需进行任何更改。调用 smtplib.SMTP('localhost')
将连接到主机上的 SMTP 服务器 运行ning。
- 您不使用
--net=host
启动容器。然后,如果您使用 Windows 或 MacOS,则需要连接到 host.docker.internal
而不是 localhost
。如果您使用 Linux,可能需要使用另一个 trick。本质上,代码仍然连接到主机上的 SMTP 服务器 运行ning。
- 您将 SMTP 服务器和 python stmp 客户端应用程序(您共享的代码)打包在同一个 Docker 映像中。这是不好的做法,应该避免。不过你可以按照docs来实现。
请分享以下内容以更好地理解问题:
更具体地说:
OS你在用。 Docker for desktop 在网络功能方面与 Mac 和 Windows、especially 的行为不同。
Dockerfile
你用。否则不可能 运行 图像并复制您面临的问题并理解您所说的 sendmail service is running in my container.
的意思
完全可用的 python 代码(包括导入等...)否则,不清楚 smtplib
您使用的是什么。
文档链接。如果你使用标准库smtplib
,那么它的docs没有这样的描述:
sendmail method description has this:
... the message was accepted for delivery to three of the four addresses, and one was rejected, with the error code 550. If all
addresses are accepted, then the method will return an empty
dictionary.
我想用 python 上的 smtp
库发送邮件。我知道它在端口号 25 上使用本地 smtp 服务。我有以下代码。这些代码 运行 在我的本地没有任何问题,邮件发送成功。但是当我将它们移动到 docker 容器时,邮件不会发送,也不会给出任何错误。
我的代码:
from_mail = 'noreply@testmail.com'
to_mail = 'to@testmail.com'
s = smtplib.SMTP('localhost')
subject = 'Test Subject'
content = 'content test'
message = f"""\
Subject: {subject}
To: {to_mail}
From: {from_mail}
{content}"""
result = s.sendmail(from_mail, to_mail, message)
s.quit()
在 运行 执行这些代码后,我得到空字典 ({}) 作为 result
值。在sendmail方法描述中有这样的:
... the message was accepted for delivery to three of the four addresses, and one was rejected, with the error code 550. If all addresses are accepted, then the method will return an empty dictionary.
是关于网络配置的吗?我应该配置任何网络设置吗?
默认情况下,docker 容器 运行 在单独的网络堆栈中,因此 localhost
与 docker 容器内的含义不同您的代码 运行 直接在您的计算机上。
根据您的 SMTP 服务器的设置方式,它也可能被配置为拒绝发送任何电子邮件,但那些直接来自您的计算机的电子邮件,并且 docker 容器可能被视为不应该发送的外来者通过它发送电子邮件。
我想最简单的解决方案是 运行 您的 docker 容器 --net=host
。有了这个,docker 容器的网络堆栈将与您计算机的堆栈相同,一切都应该像代码 运行ning 直接在 docker.[=12= 之外一样工作。 ]
如果它在主机上运行,请尝试使用主机 IP 而不是 localhost
。
s = smtplib.SMTP(HOST_IP)
或者按照 Arthur 的建议,您可以使用 --net=host
运行 主机网络中的容器,然后继续使用 localhost
。
您共享的代码是 SMTP 客户端应用程序。假设使用 SMTP 客户端标准库 smtplib
并且 SMTP 服务器在本地主机上 运行ning,代码将在以下条件下在 Docker 容器中运行:
- 您使用
--net=host
启动容器,则无需进行任何更改。调用smtplib.SMTP('localhost')
将连接到主机上的 SMTP 服务器 运行ning。 - 您不使用
--net=host
启动容器。然后,如果您使用 Windows 或 MacOS,则需要连接到host.docker.internal
而不是localhost
。如果您使用 Linux,可能需要使用另一个 trick。本质上,代码仍然连接到主机上的 SMTP 服务器 运行ning。 - 您将 SMTP 服务器和 python stmp 客户端应用程序(您共享的代码)打包在同一个 Docker 映像中。这是不好的做法,应该避免。不过你可以按照docs来实现。
请分享以下内容以更好地理解问题:
更具体地说:
OS你在用。 Docker for desktop 在网络功能方面与 Mac 和 Windows、especially 的行为不同。
的意思Dockerfile
你用。否则不可能 运行 图像并复制您面临的问题并理解您所说的sendmail service is running in my container.
完全可用的 python 代码(包括导入等...)否则,不清楚
smtplib
您使用的是什么。文档链接。如果你使用标准库
smtplib
,那么它的docs没有这样的描述:
sendmail method description has this:
... the message was accepted for delivery to three of the four addresses, and one was rejected, with the error code 550. If all addresses are accepted, then the method will return an empty dictionary.