30

我在用 Python 发送电子邮件时遇到了一个小问题:

#me == my email address
#you == recipient's email address
me = "some.email@gmail.com"
you = "some_email2@gmail.com"

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Alert"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).
html = '<html><body><p>Hi, I have the following alerts for you!</p></body></html>'

# Record the MIME types of both parts - text/plain and text/html.
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part2)

# Send the message via local SMTP server.
s = smtplib.SMTP('aspmx.l.google.com')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()

所以在此之前,我的程序没有给我一个错误,但它也没有给我发送电子邮件。现在python给了我一个错误:

SMTPServerDisconnected: Connection unexpectedly closed

我怎样才能解决这个问题?

4

6 回答 6

21

TLDR:通过 TLS 切换到经过身份验证的连接。

很可能gmail服务器在data命令之后拒绝了连接(在这个阶段他们这样做非常讨厌:)。实际的消息很可能是这个:

    retcode (421); Msg: 4.7.0 [ip.octets.listed.here      15] Our system has detected an unusual rate of
    4.7.0 unsolicited mail originating from your IP address. To protect our
    4.7.0 users from spam, mail sent from your IP address has been temporarily
    4.7.0 rate limited. Please visit
    4.7.0  https://support.google.com/mail/answer/81126 to review our Bulk Email
    4.7.0 Senders Guidelines. qa9si9093954wjc.138 - gsmtp

我怎么知道?因为我已经尝试过 :) 使用s.set_debuglevel(1),它会打印 SMTP 对话,您可以直接看到问题所在。

您在这里有两个选择:

  1. 继续使用该继电器;正如谷歌所解释的,它只是未加密的 gmail-to-gmail,你必须通过他们的程序取消你的 ip 黑名单

  2. 最万无一失的选择是切换到带有身份验证的 TLS

更改后的源如下所示:

# skipped your comments for readability
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

me = "some.email@gmail.com"
my_password = r"your_actual_password"
you = "some.email2@gmail.com"

msg = MIMEMultipart('alternative')
msg['Subject'] = "Alert"
msg['From'] = me
msg['To'] = you

html = '<html><body><p>Hi, I have the following alerts for you!</p></body></html>'
part2 = MIMEText(html, 'html')

msg.attach(part2)

# Send the message via gmail's regular server, over SSL - passwords are being sent, afterall
s = smtplib.SMTP_SSL('smtp.gmail.com')
# uncomment if interested in the actual smtp conversation
# s.set_debuglevel(1)
# do the smtp auth; sends ehlo if it hasn't been sent already
s.login(me, my_password)

s.sendmail(me, you, msg.as_string())
s.quit()

现在,如果尝试“欺骗”系统并使用不同的(非 gmail)地址发送,它将 a)要求您连接到不同的主机名(gmail 的一些 MX 记录),然后 b)阻止您并关闭基于被列入黑名单的 IP 的连接,以及 c) 执行反向 DNS、DKIM 和许多其他对策,以确保您实际上控制了您在 MAIL FROM: 地址中提供的域。

最后,还有选项 3) - 使用任何其他电子邮件中继服务,有很多好的 :)

于 2015-10-14T09:10:20.113 回答
14

我有同样的问题并通过指定正确的端口来解决它,如下所示:

smtplib.SMTP('smtp.gmail.com', 587)
于 2017-04-21T21:34:02.813 回答
4

使用smtplib.SMTP_SSL()代替smtplib.SMTP()对我有用。尝试这个。

于 2017-10-02T07:39:16.203 回答
1

我意识到了一个奇怪的行为。我使用了提到问题和答案的类似代码。我的代码最近几天一直在工作。但是,今天我遇到了问题中提到的错误消息。

我的解决方案:我通过图书馆网络尝试了我的成功尝试。今天我通过星巴克网络(通过强制门户)尝试了它。我将其更改为我的移动网络。它又开始工作了。

谷歌可能会拒绝来自不可靠网络的请求。

于 2017-12-27T17:29:56.387 回答
0

我面临着同样的问题。就我而言,几天前就更改了密码。所以,它给出了错误。当我在代码中更新密码时,它就像一个魅力......!!!

于 2018-06-12T09:25:15.937 回答
-1

Googlers:我有一个在本地运行的测试 smtp 服务器。我收到此错误是因为我在关闭客户端 smtp 之前关闭了本地 smtp 服务器。

于 2019-05-01T15:34:26.517 回答