gpt4 book ai didi

python - 从(Python)代码实际发送邮件的正确方法是什么?

转载 作者:太空狗 更新时间:2023-10-29 18:08:00 24 4
gpt4 key购买 nike

免责声明 :由于这个问题的广泛性质(见下文;-),我对标题犹豫不决,其他选项包括:

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


  • 一、 一点上下文 :
    为了学习,我正在构建一个具有用户注册功能的网站。这个想法是注册后用户将收到一封带有激活链接的电子邮件。我想用 Python 代码撰写和发送电子邮件,这就是我想要求澄清的部分。

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

    My naive understanding

    在搜索示例后,我在 stackoverflow 上遇到了一些问题和答案( 1234 )。从这些中,我提炼了以下代码段,以从 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' .从评论到 this answer ,我发现本地 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 代码)。

    所以,下一步是设置一个本地 SMTP 服务器,能够将电子邮件发送到外部“真实世界”的电子邮件地址(因为我想从 Python 代码中完成这一切,所以服务器本身最好在Python也是)。我记得在一些杂志上读到过(2000 年初),垃圾邮件发送者使用本地服务器发送邮件(那篇特定文章谈论的是 Sambar,其开发已于 2007 年结束,并且不是用 Python 编写的 :-) 我认为应该有一些具有类似功能的当今解决方案。所以我开始搜索,我希望找到(在 stackoverflow 或其他地方)一个相当短的代码片段,它会做我想要的。我还没有找到这样的代码片段,但我遇到了一个标题为 (Python) Send Email without Mail Server 的片段。 (它使用 chilkat API),虽然我所需要的(据说)就在那里,但在代码注释中,第一行明确指出:

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



    和下面的几行:

    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.



    读到这些,让我明白了——显然,我对这个过程的理解(反射(reflect)在上图)中缺乏一些细节。为了纠正这个问题,我已经阅读了整篇 RFC on SMTP .

    阅读 RFC 后, 我改进的理解 过程,大概是这样的:
    My improved understanding

    从这个理解,来了 实际问题我想澄清一下:
  • 作为一般情况,我的“改进的理解”可以被认为是正确的吗?
  • MX 查找究竟返回哪些地址?
  • 使用 host -t mx gmail.com命令(由 this answer 建议),我能够检索到以下内容:
    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.
  • 但这些都没有在 official docs 中提及(那些在那里: smtp-relay.gmail.comsmtp.gmail.comaspmx.l.google.com )
  • 是否总是需要身份验证才能将电子邮件传递给已建立的邮件服务(例如 gmail)的 SMTP 服务器?
  • 我知道要使用,比如 smtp.gmail.com对于邮件提交,无论收件人是否拥有 @gmail,您都需要地址与否(如 docs 中所述):

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

  • 但是,如果发送电子邮件至 user@gmail.com提交给不属于 gmail 的 SMTP 服务器,然后它将被重定向到其中一台 gmail 服务器(直接或通过网关/中继)。在这种情况下(我假设)电子邮件的发件人只需要在邮件提交时进行身份验证,那么在此之后 gmail 服务器将在没有身份验证的情况下接受邮件?
  • 如果是,是什么阻止我“假装”成为这样的网关/中继并将电子邮件直接移交给他们指定的 SMTP?然后,编写“代理 SMTP”也应该很容易,它只会通过 MX 查找搜索合适的服务器,然后直接将电子邮件发送给它。
  • Documentation on gmail SMTP ,还提到了 aspmx.l.google.com服务器,但不需要身份验证:

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



    话虽如此,我认为以下代码段应该有效,用于向 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 的通信在代码中正确处理。
  • 最佳答案

    您对邮件工作原理的理解大致正确。一些可以解决问题的附加说明:

  • SMTP 用于两个不同的目的。你似乎混淆了这两个。:
  • 第一个用途,通常称为“提交”,是将邮件从 MUA(邮件用户代理、您的邮件程序、Outlook、Thunderbird 等)发送到 MTA(邮件传输代理,通常称为“邮件服务器”) . MTA 由您的 ISP 运行,或通过邮件提供商(例如 GMail)。通常,它们的使用受到 IP 地址(只有所述 ISP 的客户可以使用它)或用户名/密码的限制。
  • 第二种用途是将邮件从一个 MTA 发送到另一个 MTA。这部分通常是开放的,因为您可能愿意接受来自任何人的入站邮件。这也是采取反垃圾邮件措施的地方。

  • 为了发送邮件,您至少需要 SMTP 的第二部分:与另一个 MTA 交谈以传递邮件的能力。

    发送邮件的典型方式是在您的应用程序中编写邮件,然后将其发送到 MTA 邮件服务器以进行递送。根据您的设置,该 MTA 可以安装在运行 Python 代码的同一台机器上(本地主机),也可以是更“中央”的邮件服务器(可能需要身份验证)。

    “您的” MTA 将处理所有令人讨厌的邮件投递细节,例如:
  • 执行 DNS 查找以找出要联系以中继邮件的 MTA。这包括 MX 查找,以及其他回退机制,例如 A-records .
  • 重试投递,如果第一次尝试暂时失败
  • 如果消息永久失败,则生成退回消息
  • 制作邮件的多个副本,以防不同域中有多个收件人
  • 使用 DKIM 签署消息以减少它被标记为垃圾邮件的机会。
  • ...

  • 当然,您可以在自己的 Python 代码中重新实现所有这些功能,并有效地将 MTA 与您的应用程序结合起来,但我强烈建议不要这样做。邮件出人意料地难以正确...

    底线:尝试通过 SMTP 将邮件发送到您的提供商或其他邮件服务的邮件服务器。如果这是不可能的:如果您想运行自己的邮件服务器,请认真考虑。被标记为垃圾邮件发送者很容易;从垃圾邮件列表中删除要困难得多。不要在您的应用程序中重新实现 SMTP 代码。

    关于python - 从(Python)代码实际发送邮件的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50695188/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com