如何使用Python以提供者的身份通过Gmail发送电子邮件?


289

我正在尝试使用python发送电子邮件(Gmail),但出现以下错误。

Traceback (most recent call last):  
File "emailSend.py", line 14, in <module>  
server.login(username,password)  
File "/usr/lib/python2.5/smtplib.py", line 554, in login  
raise SMTPException("SMTP AUTH extension not supported by server.")  
smtplib.SMTPException: SMTP AUTH extension not supported by server.

Python脚本如下。

import smtplib
fromaddr = 'user_me@gmail.com'
toaddrs  = 'user_you@gmail.com'
msg = 'Why,Oh why!'
username = 'user_me@gmail.com'
password = 'pwd'
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

16
既然Google正朝着通过gmail发送消息的内部API迈进,那么应该解锁这个问题。这一举动使所有这些答案中的一个都变得过时了,而一个相关的答案在实际解决问题上非常轻巧。
安德鲁

另外,对于VPN用户,如果问题仍然存在,请关闭VPN。那对我有用。
保罗

Answers:


211

您需要先说一下EHLO才能直接进入STARTTLS

server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()

此外,你应该真正创造From:To:以及Subject:邮件标题,一个空行,并使用从邮件正文中分离出来CRLF作为EOL标志。

例如

msg = "\r\n".join([
  "From: user_me@gmail.com",
  "To: user_you@gmail.com",
  "Subject: Just a message",
  "",
  "Why, oh why"
  ])

2
调用server.sendmail(fromaddr,toaddrs,msg)第二个参数,toaddrs必须是列表,toaddrs = ['user_me@gmail.com']
Massimo Fazzolari

14
随着2014年8月的现在,这引起了smtplib.SMTPAuthenticationError:(534,“5.7.9应用专用密码需要。
anon58192932

7
对于我来说,虽然,我不得不启用“应用”密码登录使用@google帐户通过Python可以发送电子邮件:support.google.com/accounts/answer/...
anon58192932

1
下面是有关如何使用邮件多人的链接:stackoverflow.com/questions/8856117/...
anon58192932

1
我曾经通过telnet登录到SMTP服务器并EHLO通过错字发送。在我尝试了很多次HELO之后,反应却有所不同。花了几个小时才弄清楚EHLO实际上是SMTP可以理解的命令,我做了错字。
Shiplu Mokaddim

297
def send_email(user, pwd, recipient, subject, body):
    import smtplib

    FROM = user
    TO = recipient if isinstance(recipient, list) else [recipient]
    SUBJECT = subject
    TEXT = body

    # Prepare actual message
    message = """From: %s\nTo: %s\nSubject: %s\n\n%s
    """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    try:
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.ehlo()
        server.starttls()
        server.login(user, pwd)
        server.sendmail(FROM, TO, message)
        server.close()
        print 'successfully sent the mail'
    except:
        print "failed to send mail"

如果要使用端口465,则必须创建一个SMTP_SSL对象:

# SMTP_SSL Example
server_ssl = smtplib.SMTP_SSL("smtp.gmail.com", 465)
server_ssl.ehlo() # optional, called by login()
server_ssl.login(gmail_user, gmail_pwd)  
# ssl server doesn't support or need tls, so don't call server_ssl.starttls() 
server_ssl.sendmail(FROM, TO, message)
#server_ssl.quit()
server_ssl.close()
print 'successfully sent the mail'

2
非常好的样品谢谢。我注意到的一个想法是,如果我想使用SSL连接,则必须删除server.starttls()
Dowlers

18
不幸的是,它不再起作用:smtplib.SMTPAuthenticationError:(534,'5.7.14 < accounts.google.com / ... ...请通过网络浏览器登录,\ n5.7.14然后重试。\ n5.7.14了解更在\ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ...然后我接到了谷歌邮件,即出现了可疑的连接尝试。
royskatt

13
@royskatt-您要做的就是创建一个应用密码,并使用它代替您的帐户密码。在此处创建应用密码:security.google.com/settings/security/apppasswords
Jared,2015年

15
@royskatt:我刚刚解决了您面临的问题。Google设置为允许访问安全性较低的应用,您只需将其打开即可。您可以从以下位置到达那里:
Google-

2
如果您的gmail是通过双向身份验证进行保护的,则必须首先生成一个应用专用密码 ->然后在上面的示例代码中使用该应用密码(这很重要,因为这样您就不会在任何地方写下密码了以明文形式,您可以随时撤消应用密码)。
特雷弗·博伊德·史密斯

136

我遇到了类似的问题,偶然发现了这个问题。我收到SMTP身份验证错误,但我的用户名/密码正确。这是修复它的原因。我读到这个:

https://support.google.com/accounts/answer/6010255

简而言之,Google不允许您通过smtplib登录,因为它已将这种登录标记为“安全性较低”,因此您要做的就是在登录google帐户时转到此链接,并允许访问:

https://www.google.com/settings/security/lesssecureapps

设置好之后(请参见下面的屏幕截图),它应该可以工作。

在此处输入图片说明

现在可以登录:

smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo()
smtpserver.login('me@gmail.com', 'me_pass')

更改后的响应:

(235, '2.7.0 Accepted')

事先回应:

smtplib.SMTPAuthenticationError: (535, '5.7.8 Username and Password not accepted. Learn more at\n5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257 g66sm2224117qgf.37 - gsmtp')

还是行不通?如果仍然收到SMTPAuthenticationError,但现在的代码为534,则因为位置未知。点击此链接:

https://accounts.google.com/DisplayUnlockCaptcha

单击继续,这将给您10分钟的时间注册新应用。因此,现在就进行另一次登录尝试,它应该可以工作。

更新:这似乎无法立即生效,您可能会在smptlib中遇到此错误一段时间:

235 == 'Authentication successful'
503 == 'Error: already authenticated'

该消息显示使用浏览器登录:

SMTPAuthenticationError: (534, '5.7.9 Please log in with your web browser and then try again. Learn more at\n5.7.9 https://support.google.com/mail/bin/answer.py?answer=78754 qo11sm4014232igb.17 - gsmtp')

启用“ lesssecureapps”后,去喝杯咖啡,回来,然后再次尝试“ DisplayUnlockCaptcha”链接。根据用户的经验,更改可能最多需要一个小时才能生效。然后再次尝试登录过程。


3
是的,谢谢 !使用烧瓶邮件时发生
Giannis 2014年

1
谢谢男人对我的唯一问题:accounts.google.com/DisplayUnlockCaptcha
Limitless isa 2015年

6
此外,请保留半小时到一个小时以更改设置。我创建了一个新帐户,禁用了所有增加的安全性,但仍然遇到相同的错误。大约一个小时后,一切正常。
jkgeyti's

2
如果您启用了“两步验证”,则无法启用安全性较低的应用。最好和最安全的选择是按照建议的那样启用“ apppassword” security.google.com/settings/security/apppasswords,它的工作原理就像是一种魅力
Omiod

2
当我点击apppasswords链接时,我所有的Google帐户都收到“您正在寻找的设置不适用于您的帐户”错误。
苏珊妮

18

你对OOP失望吗?

#!/usr/bin/env python


import smtplib

class Gmail(object):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        self.server = 'smtp.gmail.com'
        self.port = 587
        session = smtplib.SMTP(self.server, self.port)        
        session.ehlo()
        session.starttls()
        session.ehlo
        session.login(self.email, self.password)
        self.session = session

    def send_message(self, subject, body):
        ''' This must be removed '''
        headers = [
            "From: " + self.email,
            "Subject: " + subject,
            "To: " + self.email,
            "MIME-Version: 1.0",
           "Content-Type: text/html"]
        headers = "\r\n".join(headers)
        self.session.sendmail(
            self.email,
            self.email,
            headers + "\r\n\r\n" + body)


gm = Gmail('Your Email', 'Password')

gm.send_message('Subject', 'Message')

33
如果您的类只有两种方法,其中一种是__init__,则只需使用一个函数即可。
JoeQuery 2014年

您将如何使用这种方法添加附件?
sgerbhctim

如果您想初始化客户端并将其传递给代码的其他部分,而不是传递电子邮件和密码,则使用类会很好。或者,如果您想发送多条消息而不每次都输入电子邮件和密码。
Sami从

15

这个作品

创建Gmail APP密码!

创建之后,请创建一个名为 sendgmail.py

然后添加以下代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# =============================================================================
# Created By  : Jeromie Kirchoff
# Created Date: Mon Aug 02 17:46:00 PDT 2018
# =============================================================================
# Imports
# =============================================================================
import smtplib

# =============================================================================
# SET EMAIL LOGIN REQUIREMENTS
# =============================================================================
gmail_user = 'THEFROM@gmail.com'
gmail_app_password = 'YOUR-GOOGLE-APPLICATION-PASSWORD!!!!'

# =============================================================================
# SET THE INFO ABOUT THE SAID EMAIL
# =============================================================================
sent_from = gmail_user
sent_to = ['THE-TO@gmail.com', 'THE-TO@gmail.com']
sent_subject = "Where are all my Robot Women at?"
sent_body = ("Hey, what's up? friend!\n\n"
             "I hope you have been well!\n"
             "\n"
             "Cheers,\n"
             "Jay\n")

email_text = """\
From: %s
To: %s
Subject: %s

%s
""" % (sent_from, ", ".join(sent_to), sent_subject, sent_body)

# =============================================================================
# SEND EMAIL OR DIE TRYING!!!
# Details: http://www.samlogic.net/articles/smtp-commands-reference.htm
# =============================================================================

try:
    server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    server.ehlo()
    server.login(gmail_user, gmail_app_password)
    server.sendmail(sent_from, sent_to, email_text)
    server.close()

    print('Email sent!')
except Exception as exception:
    print("Error: %s!\n\n" % exception)

因此,如果成功,将看到如下图像:

我通过向自己发送电子邮件和向自己发送电子邮件进行了测试。

发送成功的电子邮件。

注意:我的帐户启用了两步验证。应用密码与此配合使用!(对于gmail smtp设置,您必须转到https://support.google.com/accounts/answer/185833?hl=zh_CN并执行以下步骤)

此设置不适用于启用了两步验证的帐户。此类帐户需要特定于应用程序的密码,以降低安全性。

安全性较低的应用访问权限...此设置不适用于启用了两步验证的帐户。


1
很棒的解决方案,在代码中有很好的解释。谢谢杰,非常感谢。愚蠢的问题:您知道每天(使用gmail)可以发送的电子邮件的最大限制是多少?
安杰洛

谢谢@Angelo,但有一个限制,GMail = 500封电子邮件或500个收件人/天(参考号):support.google.com/mail/answer/22839 G SUITE与众不同,每天2000条消息,可以在这里找到:支持.google.com / a / answer / 166852祝您好运!
JayRizzo

2
所有其他职位都是较旧的职位,可能无法正常工作,但这是100%正常工作。请生成应用密码。感谢您的回答
Shubh

1
我对此解决方案没有更多支持感到有些惊讶。我还没有尝试所有其他方法,但是我已经尝试了几种方法,只有一种方法可行,修补程序为0。
mcouthon

14

您可以在这里找到它:http : //jayrambhia.com/blog/send-emails-using-python

smtp_host = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP()
server.connect(smtp_host,smtp_port)
server.ehlo()
server.starttls()
server.login(user,passw)
fromaddr = raw_input('Send mail by the name of: ')
tolist = raw_input('To: ').split()
sub = raw_input('Subject: ')

msg = email.MIMEMultipart.MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = email.Utils.COMMASPACE.join(tolist)
msg['Subject'] = sub  
msg.attach(MIMEText(raw_input('Body: ')))
msg.attach(MIMEText('\nsent via python', 'plain'))
server.sendmail(user,tolist,msg.as_string())

2
加1,因为构建MIME比对您自己的格式字符串进行硬编码更好。简单文本消息是否需要MIMEMultipart?还是下面的方法也正确:stackoverflow.com/a/6270987/895245
Ciro Santilli郝海东冠状病六四事件法轮功2015年

您在哪里实例化email变量?
madcat

11

没有直接关系,但仍然值得指出的是,我的程序包试图使发送Gmail消息真正快速而轻松。它还尝试维护错误列表,并尝试立即指向解决方案。

实际上,只需要此代码即可完成您编写的操作:

import yagmail
yag = yagmail.SMTP('user_me@gmail.com')
yag.send('user_you@gmail.com', 'Why,Oh why!')

或一个班轮:

yagmail.SMTP('user_me@gmail.com').send('user_you@gmail.com', 'Why,Oh why!')

对于软件包/安装,请查看gitpip,它们可用于Python 2和3。


9

这是一个Gmail API示例。尽管更复杂,但这是我发现的唯一一种在2019年有效的方法。该示例摘自并修改自:

https://developers.google.com/gmail/api/guides/sending

您需要通过其网站使用Google API接口创建一个项目。接下来,您需要为您的应用启用GMAIL API。创建凭据,然后下载这些凭据,将其另存为凭据.json。

import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

from email.mime.text import MIMEText
import base64

#pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly', 'https://www.googleapis.com/auth/gmail.send']

def create_message(sender, to, subject, msg):
    message = MIMEText(msg)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject

    # Base 64 encode
    b64_bytes = base64.urlsafe_b64encode(message.as_bytes())
    b64_string = b64_bytes.decode()
    return {'raw': b64_string}
    #return {'raw': base64.urlsafe_b64encode(message.as_string())}

def send_message(service, user_id, message):
    #try:
    message = (service.users().messages().send(userId=user_id, body=message).execute())
    print( 'Message Id: %s' % message['id'] )
    return message
    #except errors.HttpError, error:print( 'An error occurred: %s' % error )

def main():
    """Shows basic usage of the Gmail API.
    Lists the user's Gmail labels.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('gmail', 'v1', credentials=creds)

    # Example read operation
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])

    if not labels:
        print('No labels found.')
    else:
        print('Labels:')
    for label in labels:
        print(label['name'])

    # Example write
    msg = create_message("from@gmail.com", "to@gmail.com", "Subject", "Msg")
    send_message( service, 'me', msg)

if __name__ == '__main__':
    main()

smtplib并不是完全线程安全的,因此在发送并发消息时会遇到问题。这是正确的方法。
dsbajna

2

现在有一个gmail API,可让您通过REST发送电子邮件,阅读电子邮件和创建草稿。与SMTP调用不同,它是非阻塞的,这对于基于线程的Web服务器在请求线程中发送电子邮件(例如python Web服务器)可能是一件好事。该API也非常强大。

  • 当然,应该将电子邮件传递到非Web服务器队列,但是有选项很高兴。

如果您对域具有Google Apps管理员权限,那么设置起来最容易,因为这样您就可以授予客户一揽子许可。否则,您必须摆弄OAuth身份验证和权限。

这是一个证明它的要点:

https://gist.github.com/timrichardson/1154e29174926e462b7a


2

@David的好答案,这是针对不带通用try-except的Python 3的:

def send_email(user, password, recipient, subject, body):

    gmail_user = user
    gmail_pwd = password
    FROM = user
    TO = recipient if type(recipient) is list else [recipient]
    SUBJECT = subject
    TEXT = body

    # Prepare actual message
    message = """From: %s\nTo: %s\nSubject: %s\n\n%s
    """ % (FROM, ", ".join(TO), SUBJECT, TEXT)

    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.ehlo()
    server.starttls()
    server.login(gmail_user, gmail_pwd)
    server.sendmail(FROM, TO, message)
    server.close()

2

在您的gmail帐户上启用安全性较低的应用并使用(Python> = 3.6):

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

gmailUser = 'XXXXX@gmail.com'
gmailPassword = 'XXXXX'
recipient = 'XXXXX@gmail.com'

message = f"""
Type your message here...
"""

msg = MIMEMultipart()
msg['From'] = f'"Your Name" <{gmailUser}>'
msg['To'] = recipient
msg['Subject'] = "Subject here..."
msg.attach(MIMEText(message))

try:
    mailServer = smtplib.SMTP('smtp.gmail.com', 587)
    mailServer.ehlo()
    mailServer.starttls()
    mailServer.ehlo()
    mailServer.login(gmailUser, gmailPassword)
    mailServer.sendmail(gmailUser, recipient, msg.as_string())
    mailServer.close()
    print ('Email sent!')
except:
    print ('Something went wrong...')

1
真的很棒的答案。最好的一堆,超级简洁。谢谢。
布鲁斯·迪安

谢谢佩德罗,您的回答解决了它。顺便说一句,适用于使用带有多个别名的Gsuite的任何人;只需在support.google.com/mail/answer/22370?hl=zh_CN之后将别名添加到您的gmail帐户,即可使用替换<{gmailUser}>为来发送别名<YourAlias>
LucSpan

1

好像是老问题了smtplib。在python2.7一切正常。

更新:是的,server.ehlo()也可以提供帮助。


-1
    import smtplib

    fromadd='from@gmail.com'
    toadd='send@gmail.com'

    msg='''hi,how r u'''
    username='abc@gmail.com'
    passwd='password'

    try:
        server = smtplib.SMTP('smtp.gmail.com:587')
        server.ehlo()
        server.starttls()
        server.login(username,passwd)

        server.sendmail(fromadd,toadd,msg)
        print("Mail Send Successfully")
        server.quit()

   except:
        print("Error:unable to send mail")

   NOTE:https://www.google.com/settings/security/lesssecureapps that                                                         should be enabled

我正在发布简单的代码,该代码将执行如何从Gmail帐户发送邮件。如果您需要任何信息,请告诉我。我希望代码能对所有用户有所帮助。
Shyam Gupta

-2
import smtplib
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login("fromaddress", "password")
msg = "HI!"
server.sendmail("fromaddress", "receiveraddress", msg)
server.quit()

使用python代码通过gmail发送邮件的简单代码。发件人地址是您的gmailID,收件人地址是您发送邮件的邮件ID。
Sam Divya Kumar 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.