smtplib和gmail - Python脚本问题

25

这是我的脚本:

#!/usr/bin/python

import smtplib
msg = 'Hello world.'

server = smtplib.SMTP('smtp.gmail.com',587) #port 465 or 587
server.ehlo()
server.starttls()
server.ehlo()
server.login('myname@gmail.com','mypass')
server.sendmail('myname@gmail.com','somename@somewhere.com',msg)
server.close()
我只是想从我的Gmail账户发送一封电子邮件。由于Gmail的要求,脚本使用了starttls。我已经在两个Web主机上尝试过,一个是1and1,另一个是webfaction。1and1给我一个“连接被拒绝”的错误,而webfaction没有报错,但是也没有发送电子邮件。我看不出脚本有什么问题,所以我认为这可能与Web主机有关。非常感谢任何想法和评论。
编辑:我打开了调试模式。从输出中看来,它似乎成功地发送了消息......我只是从未收到它。
send: 'ehlo web65.webfaction.com\r\n'
reply: '250-mx.google.com at your service, [174.133.21.84]\r\n'
reply: '250-SIZE 35651584\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-STARTTLS\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250 PIPELINING\r\n'
reply: retcode (250); Msg: mx.google.com at your service, [174.133.21.84]
SIZE 35651584
8BITMIME
STARTTLS
ENHANCEDSTATUSCODES
PIPELINING
send: 'STARTTLS\r\n'
reply: '220 2.0.0 Ready to start TLS\r\n'
reply: retcode (220); Msg: 2.0.0 Ready to start TLS
send: 'ehlo web65.webfaction.com\r\n'
reply: '250-mx.google.com at your service, [174.133.21.84]\r\n'
reply: '250-SIZE 35651584\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-AUTH LOGIN PLAIN\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250 PIPELINING\r\n'
reply: retcode (250); Msg: mx.google.com at your service, [174.133.21.84]
SIZE 35651584
8BITMIME
AUTH LOGIN PLAIN
ENHANCEDSTATUSCODES
PIPELINING
send: 'AUTH PLAIN *****\r\n'
reply: '235 2.7.0 Accepted\r\n'
reply: retcode (235); Msg: 2.7.0 Accepted
send: 'mail FROM:<myname@gmail.com> size=12\r\n'
reply: '250 2.1.0 OK 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.1.0 OK 4sm652580yxq.48
send: 'rcpt TO:<myname@gmail.com>\r\n'
reply: '250 2.1.5 OK 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.1.5 OK 4sm652580yxq.48
send: 'data\r\n'
reply: '354  Go ahead 4sm652580yxq.48\r\n'
reply: retcode (354); Msg: Go ahead 4sm652580yxq.48
data: (354, 'Go ahead 4sm652580yxq.48')
send: 'Hello world.\r\n.\r\n'
reply: '250 2.0.0 OK 1240421143 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.0.0 OK 1240421143 4sm652580yxq.48
data: (250, '2.0.0 OK 1240421143 4sm652580yxq.48')

2
你可以通过普通的SMTP中继发送邮件,而不是直接调用Gmail。 - gimel
1
你如何打开调试模式以获取输出信息? - trusktr
3
smtplib.set_debuglevel(True) 将为您提供帮助,@trusktr。 - hd1
我不明白,被接受的答案是如何解决你的问题的?我应该复制粘贴哪一段代码才能发送电子邮件? - Charlie Parker
9个回答

10

这里有一些自我宣传,但我觉得是站在合理的基础上。

您只需要使用以下代码即可完全实现您所写的内容:

import yagmail
yag = yagmail.SMTP('myname@gmail.com')
yag.send('somename@somewhere.com', subject = None, contents = 'Hello')

或者一行代码:

yagmail.SMTP('myname@gmail.com').send('somename@somewhere.com', None, 'Hello world.')

很好的一点是,我建议使用密钥环来存储您的密码,这样您的脚本中就不会出现密码泄露的风险。
您可以在解释器中运行以下命令来设置此项:
import yagmail
yagmail.register("my@gmail.com", "mypassword")

然后您可以使用以下命令退出:

import yagmail
yagmail.SMTP("my@gmail.com") # without password

如果您在主目录中添加了带有“my@gmail.com”的.yagmail文件,那么您只需执行以下操作:yagmail.SMTP(),但这现在已经没有什么意义了。
警告:如果您需要发送大量邮件,请设置OAuth2,yagmail可以帮助您完成此操作。
yagmail.SMTP("my@gmail.com", oauth2_file="/path/to/save/creds.json")

第一次运行时,它会引导您完成获取OAuth2凭据并将其存储在文件中的过程,以便下次无需再进行任何操作。 您是否怀疑有人发现了您的凭据?他们的权限受到限制,但最好通过gmail使其凭据失效。
有关包/安装,请参阅git或readthedocs,适用于Python 2和3。链接如下: git readthedocs

1
谢谢您的点赞,我真的在努力让这个软件包得到更多关注! - PascalVKooten
2
SMTPAuthenticationError: Please log in via your web browser and\n5.7.14 then try again.\n5.7.14 Learn more at\n5.7.14 https://support.google.com/mail/answer/78754 vl1sm48001045pbc.31 - gsmtp') - Amit Tripathi
1
@Death-Stalker 似乎你在输入密码时犯了一个错误? - PascalVKooten
1
@CharlieParker 这是可选的。如果您懒得阅读文档,也可以将其包含在脚本中。或者您可以设置OAuth2。所有内容都在文档中:http://yagmail.readthedocs.io/ - PascalVKooten
1
@sh37211 我建议在 Gmail 中设置一个应用程序专用密码,然后只使用该密码。 - PascalVKooten
显示剩余5条评论

8

你尝试过构建有效的消息吗?


from email.MIMEText import MIMEText

msg = MIMEText('body')
msg['Subject'] = 'subject'
msg['From'] = "..."
msg['Reply-to'] = "..."
msg['To'] = "..."

8
我不知道OP是否仍关心这个答案,但在尝试解决类似问题的过程中找到了这里,希望其他人也能从中受益。事实证明,Google已经改变了他们允许使用SMTP服务器的方式。您需要检查几件事情:
  1. 确保您正在使用与验证时相同的地址作为“发件人”地址。如果我没有弄错,过去你可以在发件人字段中放置任何你想要的内容,但出于安全考虑,现在许多SMTP主机站点(包括谷歌)将此限制为已通过身份验证的地址。
  2. 允许您的帐户被“不太安全的应用程序”访问(即:我们不从中产生收入的应用程序)。要做到这一点,请登录您的帐户并导航到这里: https://www.google.com/settings/security/lesssecureapps
  3. 使用tls的587端口。不是很确定原因,但我无法使465端口正常工作。
希望这能帮助其他人。

回答,你去哪儿了?! - O. Edholm
我感到困惑,有没有一份清晰的指南可以告诉我如何在Python中发送电子邮件? - Charlie Parker
@CharlieParker,指令可以在原始问题中找到,我的答案是为了指出可能的原因,说明OP所做的事情为什么不起作用。 - krayzk

6
我认为GMail SMTP服务器会对您连接的IP地址进行反向DNS查找,如果找不到域名,则会拒绝连接。这是为了防止垃圾邮件发送者将其SMTP服务器用作开放式中转站。

4
这可能是你的网络提供商禁止向除他们自己的smtp服务器之外的服务器进行外发连接。 - Raphaël Saint-Pierre
1
我认为这是网络服务提供商的问题。我尝试了这段代码,对我来说运行得很好。 - hwiechers
40
如果GMail进行反向DNS查找并拒绝连接,那么我如何使用我的桌面邮件客户端(例如Thunderbird)通过Gmail的SMTP发送邮件? - Piotr Findeisen


1
我访问了上述链接并有三个不同的收件地址可以发送,但是我收到了三封电子邮件,都发到了第三个地址。

http://mynthon.net/howto/-/python/python%20-%20logging.SMTPHandler-how-to-use-gmail-smtp-server.txt

import logging
import logging.handlers

class TlsSMTPHandler(logging.handlers.SMTPHandler):
def emit(self, record):
    """
    Emit a record.

    Format the record and send it to the specified addressees.
    """
    try:
        import smtplib
        import string # for tls add this line
        try:
            from email.utils import formatdate
        except ImportError:
            formatdate = self.date_time
        port = self.mailport
        if not port:
            port = smtplib.SMTP_PORT
        smtp = smtplib.SMTP(self.mailhost, port)
        msg = self.format(record)
        msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
                        self.fromaddr,
                        string.join(self.toaddrs, ","),
                        self.getSubject(record),
                        formatdate(), msg)
        if self.username:
            smtp.ehlo() # for tls add this line
            smtp.starttls() # for tls add this line
            smtp.ehlo() # for tls add this line
            smtp.login(self.username, self.password)
        smtp.sendmail(self.fromaddr, self.toaddrs, msg)
        smtp.quit()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record)

logger = logging.getLogger()

gm = TlsSMTPHandler(("smtp.gmail.com", 587), 'myusername@gmail.com', ['address1@gmail.com', 'address2@gmail.com', 'address3@gmail.com'], 'unable to find Error!', ('myusername@gmail.com', 'mypassword'))
gm.setLevel(logging.ERROR)

logger.addHandler(gm)

try:
    1/0
except:
    logger.exception('It NO work for me!!-')

1

你需要在Gmail的“已发送”文件夹中检查,因为从你的账户发给自己的邮件很可能会出现在那里。


0

它可以工作

'''
Created on 2017/11/27

@author: devuser
'''

import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate

FROM_ADDRESS = 'sender@gmail.com'
MY_PASSWORD = 'password'
TO_ADDRESS = 'receiver@test.co.jp'
BCC = 'receiver2@test.net'
SUBJECT = 'GmailのSMTPサーバ経由'
BODY = 'pythonでメール送信'


def create_message(from_addr, to_addr, bcc_addrs, subject, body):
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = from_addr
    msg['To'] = to_addr
    msg['Bcc'] = bcc_addrs
    msg['Date'] = formatdate()
    return msg


def send(from_addr, to_addrs, msg):
    smtpobj = smtplib.SMTP('smtp.gmail.com', 587)
    smtpobj.ehlo()
    smtpobj.starttls()
    smtpobj.ehlo()
    smtpobj.login(FROM_ADDRESS, MY_PASSWORD)
    smtpobj.sendmail(from_addr, to_addrs, msg.as_string())
    smtpobj.close()


if __name__ == '__main__':

    to_addr = TO_ADDRESS
    subject = SUBJECT
    body = BODY

    msg = create_message(FROM_ADDRESS, to_addr, BCC, subject, body)
    send(FROM_ADDRESS, to_addr, msg)

https://qiita.com/okhrn/items/630a87ce1a44778bbeb1


0

我遇到了同样的问题,但在尝试了上面所有的建议后,关闭 VPN 有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接