使用Python发送邮件时遇到问题
我写了这样的代码
import smtplib
server=smtplib.SMTP('localhost')
然后出现了一个错误,内容是:
错误:[Errno 10061] 无法连接,因为目标机器主动拒绝了连接
我对SMTP还很陌生,你能告诉我到底出了什么问题吗?
3 个回答
要使用Python的SMTP模块发送电子邮件,你需要找到一个有效的邮件交换器(MX)的名字。这可以是你自己本地的邮件中心或者智能中继,或者你可以通过DNS查询每个目标主机/域名的公共MX记录。
这个要求在文档中没有详细说明。Python的标准库里没有提供一个简单的方法来查询DNS的MX记录,这真是个大缺陷。(不过,有一些很不错的第三方Python DNS库,比如DNSPython和PyDNS,它们支持的DNS功能远比你发送邮件所需的要多。)
一般来说,使用你自己网络(或者互联网服务提供商)的邮件中心或中继的列表会更好。这是因为如果你直接向公开的MX主机发送邮件,可能会遇到各种反垃圾邮件的措施。(例如,在咖啡店、酒店的无线网络,或者普通家庭的有线和DSL连接上,通常是无法发送邮件的;这些地址范围在各种数据库中被列为潜在的垃圾邮件来源。)在这种情况下,你可以通过任何你喜欢的方式存储和/或获取本地邮件中心(或智能中继)的名字/地址。可以用.cfg文件(ConfigParser),或者通过LDAP或SQL查询,甚至(哎呀!)硬编码到你的脚本里。
但是,如果你的代码是打算在合适的网络上运行(比如在机房或数据中心),那么你就需要自己进行MX解析。你可以安装前面提到的PyPI包。如果你想限制使用标准库,那么你可以依赖大多数Linux、MacOS X、Solaris、FreeBSD等操作系统自带的常用命令dig
。
在这种情况下,你可以通过subprocess.Popen()
调用类似dig +short aol.com mx | awk '{print $NF}'
的命令,这可以用一个看起来不太优雅的单行代码来实现:
mxers = subprocess.Popen("dig +short %s mx | awk '{print $NF}'"
% target_domain, stdout=subprocess.PIPE,
shell=True).communicate()[0].split()
然后你可以尝试依次与每个结果主机名建立SMTP连接。(只要你的“target_domain”值经过适当处理,这样做是没问题的;不要将不可信的数据通过Popen()
传入shell=True
。)
更安全的版本看起来会更复杂:
mxers = subprocess.Popen(["dig", "+short", target_domain, "mx"],
stdout=subprocess.PIPE).communicate()[0].split()[1::2]
... 其中最后的切片/步长替代了对awk
的调用,从而避免了需要shell=True
。
听起来你正在使用的电脑上没有设置SMTP。你可以试试用你网络服务提供商的邮件服务器(通常是类似mail.example.com这样的地址),或者确保你本地安装了一个SMTP服务器。
与其在本地安装smtp库,不如在控制台上设置一个简单的smtp服务器。
你可以这样做:
python -m smtpd -n -c DebuggingServer localhost:1025
这样所有的邮件都会在控制台上显示出来。