免责声明 :由于该问题的广泛性(请参阅下面的;-),我对标题犹豫不决,其他选项包括:
首先,介绍 一些内容 : 为了学习,我正在构建一个具有用户注册功能的网站。这个想法是,注册后用户将收到带有激活链接的电子邮件。我想编写和发送来自Python代码的电子邮件,这是我想要澄清的部分。
我的理解,在我开始之前 (显然是天真=)可以用这样的方式说明(假设存在合法的电子邮件地址 user@example.com ):
搜索的例子后,我碰上#1)。从中我提取了以下代码片段,以编写并发送来自Python代码的电子邮件:
import smtplib from email.message import EmailMessage message = EmailMessage() message.set_content('Message content here') message['Subject'] = 'Your subject here' message['From'] = 'me@example.com' message['To'] = 'user@example.com' smtp_server = smtplib.SMTP('smtp.server.address:587') smtp_server.send_message(message) smtp_server.quit()
下一个(显而易见的)问题是传递给smtplib.SMTP()而不是'smtp.server.address:587'。从对这个答案的评论中,我发现本地SMTP服务器(虽然仅用于测试目的)可以通过启动python3 -m smtpd -c DebuggingServer -n localhost:1025,然后smtp_server = smtplib.SMTP('smtp.server.address:587')可以更改为,smtp_server = smtplib.SMTP('localhost:1025')并且所有发送的电子邮件都将显示在控制台中(从中python3 -m smtpd -c DebuggingServer -n localhost:1025执行命令)。足以进行测试-这不是我想要的(我的目标是- 仅使用Python代码就能从本地计算机向“真实”电子邮件地址发送邮件的功能)。
smtplib.SMTP()
'smtp.server.address:587'
python3 -m smtpd -c DebuggingServer -n localhost:1025
smtp_server = smtplib.SMTP('smtp.server.address:587')
smtp_server = smtplib.SMTP('localhost:1025')
因此,下一步将是设置本地SMTP服务器,该服务器能够将电子邮件发送到外部“真实世界”的电子邮件地址(因为我想全部通过Python代码来完成此操作,因此最好在以下位置实现服务器本身) Python也是如此)。我记得在某杂志(2000年初)中读到的内容,即垃圾邮件发送者使用本地服务器发送邮件(该特定文章谈论的是Sambar,其开发已于2007年结束,并且不是用Python编写的:-)。应该是一些具有类似功能的当今解决方案。所以我开始搜索,我的希望是(在stackoverflow或其他地方)找到一个相当短的代码段,该段代码可以满足我的要求。我没有找到这样的代码段,但是遇到了一个标题为(Python)的不带邮件服务器的发送电子邮件的代码段(使用chilkat API)(尽管我所需要的(据说)就在那儿,但在代码注释中,第一行明确指出:
是否真的可以在不连接邮件服务器的情况下发送电子邮件?并不是的。
以及以下几行:
以下是声称不需要邮件服务器的其他组件内部发生的情况:该组件使用目标收件人的电子邮件地址进行DNS MX查找,以查找该域的邮件服务器(即SMTP服务器)。然后,它连接到该服务器并发送电子邮件。您仍在连接到SMTP服务器-而不是服务器。
读完这些,使我理解了- 很明显,我对过程的理解(如上图所示)缺少一些细节。为了解决这个问题,我已经阅读了SMTP上的整个RFC。
阅读完RFC之后, 我 对过程的 理解 会变得更加生动:
通过这种理解,我想澄清一些 实际的问题 :
MX查找返回的确切地址是什么?
使用host -t mx gmail.com命令(此答案建议),我能够检索以下内容:
host -t mx gmail.com
gmail.com mail is handled by 10 alt1.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 20 alt2.gmail-smtp-in.l.google.com. gmail.com mail is handled by 40 alt4.gmail-smtp-in.l.google.com. gmail.com mail is handled by 30 alt3.gmail-smtp-in.l.google.com. gmail.com mail is handled by 5 gmail-smtp-in.l.google.com.
但这些都不在被提及的官方文档(那些不在那里smtp-relay.gmail.com,smtp.gmail.com,aspmx.l.google.com)
smtp-relay.gmail.com
smtp.gmail.com
aspmx.l.google.com
将电子邮件传递到已建立邮件服务(例如gmail)的SMTP服务器时,是否始终需要身份验证?
我知道smtp.gmail.com,无论收件人是否有@gmail地址(如docs中所述),都需要使用它来进行邮件提交:
@gmail
需要完整的Gmail或G Suite电子邮件地址才能进行身份验证。
* 但是,如果将电子邮件发送到`user@gmail.com`非gmail拥有的SMTP服务器,则它将被重定向到gmail服务器之一(直接或通过网关/中继)。在这种情况下(我假设),电子邮件的发件人只需要在邮件提交时进行身份验证,那么在此之后,gmail服务器将接受未经身份验证的邮件吗? * 如果是,是什么使我无法“假装”成为这样的网关/中继并将电子邮件直接移交给其指定的SMTP?然后,编写“ proxy-SMTP”也应该非常容易,它将通过MX查找来搜索适当的服务器,然后直接向其发送电子邮件。
邮件只能发送给Gmail或G Suite用户。
话虽如此,我认为以下代码段应该可以正常工作,以便将邮件提交到ExistingUser@gmail.com邮箱:
ExistingUser@gmail.com
import smtplib from email.message import EmailMessage message = EmailMessage() message.set_content('Message test content') message['Subject'] = 'Test mail!' message['From'] = 'me@whatever.com' message['To'] = 'ExistingUser@gmail.com' smtp_server = smtplib.SMTP('aspmx.l.google.com:25') smtp_server.send_message(message) smtp_server.quit()
运行后,上面的代码(ExistingUser@gmail.com由有效的邮件替换)将抛出OSError: [Errno 65] No route to host。我要在这里确认的是与aspmx.l.google.com代码的通信已正确处理。
OSError: [Errno 65] No route to host
我将一一讨论这些问题:
是的,一般情况下,电子邮件的发送可以这样描述:
MX查找返回服务器的地址,这些地址接收发往指定域的电子邮件。
对于接收电子邮件(即MX查找返回的电子邮件)的服务器,不需要身份验证。
有几件事可以防止此类服务器被滥用:
25
From
说了这么多,代码片段:
import smtplib from email.message import EmailMessage message = EmailMessage() message.set_content('Message content here') message['Subject'] = 'Your subject here' message['From'] = 'me@example.com' message['To'] = 'user@example.com' smtp_server = smtplib.SMTP('smtp.server.address:25') smtp_server.send_message(message) smtp_server.quit()
会实际发送一封电子邮件,因为该smtp.server.address:25服务器是合法服务器,并且在ISP和/或smtp.server.address方面没有任何阻塞。
smtp.server.address:25
smtp.server.address