从(Python)代码实际发送邮件的正确方法是什么? [英] What is the proper way to ACTUALLY SEND mail from (Python) code?

查看:164
本文介绍了从(Python)代码实际发送邮件的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

免责声明:由于该问题的广泛性(请参阅下文;-),我对标题犹豫不决,还包括其他选项:

Disclaimer: I hesitated on the title, due to the broad nature of this question (see below ;-), other options included:

  • 如何仅使用Python代码从本地主机发送邮件?
  • 如何在不使用外部SMTP服务器的情况下从Python代码发送电子邮件?
  • 是否可以仅使用localhost和Python直接将电子邮件发送到目的地?

首先,一些上下文:
为了学习,我正在建立一个具有用户注册功能的网站.这个想法是注册后用户将收到一封带有激活链接的电子邮件.我想撰写&从Python代码发送电子邮件,这是我想澄清的部分.

First, a little bit of context:
For the sake of learning I am building a website with user registration feature. The idea is that after registration user will receive an email with activation link. I would like to compose & send email from Python code, and that is the part where I would like to ask for some clarifications.

我的理解,在我开始之前(显然是天真=),可以这样说明(假设有一个合法的电子邮件地址 user@example.com ):

My understanding, before I began (obviously naive =) can be illustrated like this (given that there is a legitimate email address user@example.com):

搜索示例后,我遇到了一些问题&关于stackoverflow的答案( 1 2 3 4 ).从这些代码中,我提取了以下代码段,以编写并发送来自Python代码的电子邮件:

After searching for examples, I bumped into some questions & answers on stackoverflow (1, 2, 3, 4). From these I've distilled the following snippet, to compose and send an email from Python code:

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_server = smtplib.SMTP('smtp.server.address:587')更改为smtp_server = smtplib.SMTP('localhost:1025'),所有发送的电子邮件将显示在控制台中(从中执行python3 -m smtpd -c DebuggingServer -n localhost:1025命令),足以进行测试-这不是我想要的(我的目标是—能够仅使用Python代码从本地计算机向真实世界"的电子邮件地址发送邮件.

Next (obvious) question was what to pass to smtplib.SMTP() instead of 'smtp.server.address:587'. From the comments to this answer, I discovered that local SMTP server (just for testing purposes though) could be started via python3 -m smtpd -c DebuggingServer -n localhost:1025, then smtp_server = smtplib.SMTP('smtp.server.address:587') could be changed to smtp_server = smtplib.SMTP('localhost:1025') and all the sent emails will be displayed in the console (from where python3 -m smtpd -c DebuggingServer -n localhost:1025 command was executed), being enough for testing — it was not what I wanted (my aim was — the ability to send a mail to 'real-world' email address from local machine, using Python code only).

因此,下一步将是设置本地SMTP服务器,该服务器能够将电子邮件发送到外部真实世界"的电子邮件地址(因为我想通过Python代码来完成所有操作,因此服务器本身会更好也可以在Python中实现).我记得在某杂志上读过的文章(2000年初),垃圾邮件发送者使用本地服务器发送邮件(该特定文章在谈论(Python)发送的代码段不带邮件服务器的电子邮件(使用 chilkat API),尽管我需要做所有(据说) )就在代码注释中,第一行明确指出:

So, the next step would be to setup a local SMTP server, capable of sending an email to external 'real-world' email-address (as I wanted to do it all from Python code, so the server itself would better be implemented in Python too). I recalled reading in some magazine (in early 2000), that spammers use local servers for sending mails (that particular article was talking about Sambar, development for which have ended in 2007, and which was not written in Python :-) I thought there should be some present-day solution with similar functionality. So I started searching, my hope was to find (on stackoverflow or elsewhere) a reasonably short code snippet, which will do what I wanted. I haven't found such a code snippet, but I came across a snippet titled (Python) Send Email without Mail Server (which uses chilkat API), though all I needed (supposedly) was right there, in the comments to code, the first line clearly stated:

真的可以在不连接邮件服务器的情况下发送电子邮件吗?不是.

Is it really possible to send email without connecting to a mail server? Not really.

以及以下几行:

以下是声称不需要邮件服务器的其他组件内部发生的情况:该组件使用目标收件人的电子邮件地址进行DNS MX查找,以查找该域的邮件服务器(即SMTP服务器).然后,它连接到该服务器并发送电子邮件.您仍在连接到SMTP服务器,而不仅仅是您的服务器.

Here's what happens inside those other components that claim to not need a mail server: The component does a DNS MX lookup using the intended recipient's email address to find the mail server (i.e. SMTP server) for that domain. It then connects to that server and delivers the email. You're still connecting to an SMTP server — just not YOUR server.

读到这些,使我理解了-很明显,我对过程的理解(在上图中反映出)缺少一些细节.为了解决这个问题,我已经阅读了整个 SMTP上的RFC .

Reading that, made me understand — I, clearly, was lacking some details in my understanding (reflected on picture above) of the process. To correct this I have read the whole RFC on SMTP.

阅读RFC后,我对过程的了解可能如下所示:

After reading the RFC, my improved understanding of the process, might be pictured like this:

基于这种理解,我想澄清实际问题:

From this understanding, came the actual questions I'd like to clarify:

  1. 从总体上看,我的"理解力增强"可以被认为是正确的吗?
  2. MX查找返回的确切地址是什么?

  1. Can my "improved understanding" be considered correct, as a general picture?
  2. What addresses, exactly, are returned by MX lookup?

  • 使用host -t mx gmail.com命令(由此答案建议),我能够检索以下内容:

  • using host -t mx gmail.com command (suggested by this answer), I was able to retrieve the following:

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.comsmtp.gmail.comaspmx.l.google.com)
  • but none of these are mentioned in the official docs (ones that are there: smtp-relay.gmail.com, smtp.gmail.com, aspmx.l.google.com)
  • 是否始终需要身份验证才能将电子邮件传递到已建立的邮件服务(例如gmail)的SMTP服务器?

    Is authentication always needed to pass an email to SMTP-server of an established mail service (say gmail)?

    • 我知道您需要使用smtp.gmail.com进行邮件提交,无论收件人是否有@gmail地址(如

    • I understand that to use, say smtp.gmail.com for mail submission, you'll need, regardless if the recipient has a @gmail address or not (as it stated in docs):

    您需要完整的Gmail或G Suite电子邮件地址才能进行身份验证.

    Your full Gmail or G Suite email address is required for authentication.

  • 但是,如果将发给user@gmail.com的电子邮件提交给不属于gmail的SMTP服务器,则该电子邮件将被重定向到其中一个gmail服务器(直接或通过网关/中继).在这种情况下(我假设),电子邮件的发件人只需要在邮件提交时进行身份验证,那么在此之后,gmail服务器将接受未经身份验证的邮件吗?

  • But, if an email to user@gmail.com is submitted to SMTP-server not owned by gmail, then it'll be redirected to one of the gmail servers (directly or via gateway/relay). In this case (I assume) sender of an email will only need to authenticate on mail submission, so after that gmail server will accept the mail without authentication?

    • 如果是,是什么使我无法假装"成为这样的网关/中继并将电子邮件直接移交给其指定的SMTP?然后,编写代理SMTP"也应该非常容易,该代理将仅通过MX查找来搜索适当的服务器,然后直接向其发送电子邮件.

    有关gmail SMTP的文档,还提到了服务器,但不需要身份验证,

    Documentation on gmail SMTP, also mentions aspmx.l.google.com server, which does not require authentication, though:

    邮件只能发送给Gmail或G Suite用户.

    Mail can only be sent to Gmail or G Suite users.

    话虽如此,我认为下面的代码片段应该起作用,以便将邮件提交到ExistingUser@gmail.com邮箱:

    With that being said, I assume the following snippet should work, for submitting a mail to ExistingUser@gmail.com mailbox:

    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的通信已通过代码正确处理.

    When ran, the code above (with ExistingUser@gmail.com replaced by the valid mail) throws OSError: [Errno 65] No route to host. All I want to confirm here is that the communication to aspmx.l.google.com is handled correctly in code.

    推荐答案

    感谢这些答案,以及我的其他问题: 1 2 3 以及其他两个人的问题(和答案): —我想我现在可以自己回答自己发布的问题了.

    Thanks to these answers, to my additional questions: 1, 2, 3, as well as these two questions (and answers) of other people: one, two — I think I am now ready to answer the questions I have posted, on my own.

    我将一一解答这些问题:

    I will address the questions one by one:

    1. 是的,作为一般图片,可以这样描述电子邮件的发送:

    1. Yes, as a general picture, sending of an email can be portrayed like this:

    MX查找返回接收到发往指定域的电子邮件的服务器的地址.

    MX lookup returns address(es) of server(s) which receive email destined to the specified domain.

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆