简体   繁体   English

如何使用 Python 以 Gmail 作为提供者发送 email?

[英]How to send an email with Gmail as provider using Python?

I am trying to send email (Gmail) using python, but I am getting following error.我正在尝试使用 python 发送 email(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.

The Python script is the following. 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()
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"

if you want to use Port 465 you have to create an SMTP_SSL object:如果要使用端口 465,则必须创建SMTP_SSL object:

# 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'

You need to say EHLO before just running straight into STARTTLS :在直接进入STARTTLS之前,您需要说EHLO

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

Also you should really create From: , To: and Subject: message headers, separated from the message body by a blank line and use CRLF as EOL markers.此外,您应该真正创建From:To:Subject:邮件标题,用空行与邮件正文分隔,并使用CRLF作为 EOL 标记。

Eg例如

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

Note:笔记:

In order for this to work you need to enable "Allow less secure apps" option in your gmail account configuration.为了使其工作,您需要在 gmail 帐户配置中启用“允许安全性较低的应用程序”选项。 Otherwise you will get a "critical security alert" when gmail detects that a non-Google apps is trying to login your account.否则,当 gmail 检测到非 Google 应用程序正在尝试登录您的帐户时,您将收到“严重安全警报”。

I ran into a similar problem and stumbled on this question.我遇到了类似的问题并偶然发现了这个问题。 I got an SMTP Authentication Error but my user name / pass was correct.我收到 SMTP 身份验证错误,但我的用户名/密码是正确的。 Here is what fixed it.这是修复它的方法。 I read this:我读到这个:

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

In a nutshell, google is not allowing you to log in via smtplib because it has flagged this sort of login as "less secure", so what you have to do is go to this link while you're logged in to your google account, and allow the access:简而言之,谷歌不允许你通过 smtplib 登录,因为它已将这种登录标记为“不太安全”,所以你必须做的是 go 在你登录到你的谷歌帐户时到这个链接,并允许访问:

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

Once that is set (see my screenshot below), it should work.一旦设置好(参见下面的屏幕截图),它应该可以工作。

在此处输入图像描述

Login now works:登录现在有效:

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

Response after change:更改后的响应:

(235, '2.7.0 Accepted')

Response prior:之前的回应:

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')

Still not working?还是行不通? If you still get the SMTPAuthenticationError but now the code is 534, its because the location is unknown.如果您仍然收到 SMTPAuthenticationError 但现在代码是 534,那是因为位置未知。 Follow this link:按照这个链接:

https://accounts.google.com/DisplayUnlockCaptcha https://accounts.google.com/DisplayUnlockCaptcha

Click continue and this should give you 10 minutes for registering your new app.单击继续,这应该会给您 10 分钟的时间来注册您的新应用程序。 So proceed to doing another login attempt now and it should work.因此,现在继续进行另一次登录尝试,它应该可以工作。

UPDATE : This doesn't seem to work right away you may be stuck for a while getting this error in smptlib:更新:这似乎无法立即工作,您可能会在 smptlib 中遇到此错误一段时间:

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

The message says to use the browser to sign in:消息说使用浏览器登录:

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')

After enabling 'lesssecureapps', go for a coffee, come back, and try the 'DisplayUnlockCaptcha' link again.启用“lesssecureapps”后,go 喝杯咖啡,回来,再次尝试“DisplayUnlockCaptcha”链接。 From user experience, it may take up to an hour for the change to kick in. Then try the sign-in process again.根据用户体验,更改可能需要一个小时才能生效。然后再次尝试登录过程。

This Works这个作品

Create Gmail APP Password创建Gmail APP密码

After you create that then create a file called sendgmail.py创建之后,然后创建一个名为sendgmail.py的文件

Then add this code : 然后添加此代码

#!/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 = "Hey Friends!"
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)

So, if you are successful, will see an image like this:所以,如果你成功了,会看到这样的图像:

I tested by sending an email from and to myself.我通过向自己发送 email 进行了测试。

成功发送电子邮件。

Note: I have 2-Step Verification enabled on my account.注意:我的帐户启用了两步验证 App Password works with this, (for gmail smtp setup you must go to https://support.google.com/accounts/answer/185833?hl=en and follow the below steps) App Password works with this, (for gmail smtp setup you must go to https://support.google.com/accounts/answer/185833?hl=en and follow the below steps)

This setting is not available for accounts with 2-Step Verification enabled.此设置不适用于启用两步验证的帐户。 Such accounts require an application-specific password for less secure apps access.此类帐户需要特定于应用程序的密码才能访问不太安全的应用程序。

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

Clarification澄清

Navigate to https://myaccount.google.com/apppasswords and create an APP Password as stated above.导航到https://myaccount.google.com/apppasswords并如上所述创建 APP 密码。

https://myaccount.google.com/apppasswords

You down with OOP?你对 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')

Here is a Gmail API example.这是一个 Gmail API 示例。 Although more complicated, this is the only method I found that works in 2019. This example was taken and modified from:虽然更复杂,但这是我发现的唯一在 2019 年有效的方法。此示例取自并修改自:

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

You'll need create a project with Google's API interfaces through their website.您需要通过他们的网站使用 Google 的 API 接口创建一个项目。 Next you'll need to enable the GMAIL API for your app.接下来,您需要为您的应用启用 GMAIL API。 Create credentials and then download those creds, save it as credentials.json.创建凭据,然后下载这些凭据,将其保存为凭据.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()

You can find it here: http://jayrambhia.com/blog/send-emails-using-python你可以在这里找到它: 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())

Not directly related but still worth pointing out is that my package tries to make sending gmail messages really quick and painless.不直接相关但仍然值得指出的是,我的 package 试图使发送 gmail 消息变得非常快速和轻松。 It also tries to maintain a list of errors and tries to point to the solution immediately.它还尝试维护错误列表并尝试立即指出解决方案。

It would literally only need this code to do exactly what you wrote:从字面上看,它只需要这段代码就可以完全按照您的编写:

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

Or a one liner:或者一个班轮:

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

For the package/installation please look at git or pip , available for both Python 2 and 3.对于包/安装,请查看gitpip ,可用于 Python 2 和 3。

Enable less secure apps on your gmail account and use (Python>=3.6):在您的 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...')

Realized how painful many of the things are with sending emails via Python thus I made an extensive library for it.意识到通过 Python 发送电子邮件有多么痛苦,因此我为它制作了一个广泛的库。 It also has Gmail pre-configured (so you don't have to remember Gmail's host and port):它还预先配置了 Gmail(因此您不必记住 Gmail 的主机和端口):

from redmail import gmail
gmail.user_name = "you@gmail.com"
gmail.password = "<YOUR APPLICATION PASSWORD>"

# Send an email
gmail.send(
    subject="An example email",
    receivers=["recipient@example.com"],
    text="Hi, this is text body.",
    html="<h1>Hi, this is HTML body.</h1>"
)

Of course you need to configure your Gmail account (don't worry, it's simple):当然你需要配置你的Gmail账号(不用担心,很简单):

  1. Set up 2-step-verification (if not yet set up) 设置两步验证(如果尚未设置)
  2. Create an Application password创建应用程序密码
  3. Put the Application password to the gmail object and done将应用程序密码输入gmail object 并完成

Red Mail is actually pretty extensive (include attachments, embed images, send with cc and bcc, template with Jinja etc.) and should hopefully be all you need from an email sender. Red Mail 实际上非常广泛(包括附件、嵌入图像、使用 cc 和 bcc 发送、使用 Jinja 的模板等),希望 email 发件人提供您所需要的一切。 It is also well tested and documented.它也经过了很好的测试和记录。 I hope you find it useful.希望对你有帮助。

To install:安装:

pip install redmail

Documentation: https://red-mail.readthedocs.io/en/latest/文档: https://red-mail.readthedocs.io/en/latest/

Source code: https://github.com/Miksus/red-mail源码: https://github.com/Miksus/red-mail

Note that Gmail don't allow changing the sender.请注意,Gmail 不允许更改发件人。 The sender address is always you.发件人地址始终是您。

There is a gmail API now, which lets you send email, read email and create drafts via REST. There is a gmail API now, which lets you send email, read email and create drafts via REST. Unlike the SMTP calls, it is non-blocking which can be a good thing for thread-based webservers sending email in the request thread (like python webservers).与 SMTP 调用不同,它是非阻塞的,这对于在请求线程中发送 email 的基于线程的网络服务器(如 python 网络服务器)来说是一件好事。 The API is also quite powerful. API也相当强大。

  • Of course, email should be handed off to a non-webserver queue, but it's nice to have options.当然,email 应该交给非网络服务器队列,但有选项也不错。

It's easiest to setup if you have Google Apps administrator rights on the domain, because then you can give blanket permission to your client.如果您在域上拥有 Google Apps 管理员权限,则设置最简单,因为您可以向您的客户授予全面权限。 Otherwise you have to fiddle with OAuth authentication and permission.否则,您必须摆弄 OAuth 身份验证和权限。

Here is a gist demonstrating it:这是一个证明它的要点:

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

great answer from @David, here is for Python 3 without the generic try-except: @David 的好答案,这里是 Python 3 没有通用的 try-except :

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()

Seems like problem of the old smtplib .似乎是旧smtplib的问题。 In python2.7 everything works fine.python2.7中一切正常。

Update : Yep, server.ehlo() also could help.更新:是的, server.ehlo()也可以提供帮助。

Feb, 2022 Update: 2022 年 2 月更新:

Try 2 things to be able to send Gmail using Python .尝试2 件事,以便能够使用Gmail 发送 Python

  1. Allow less secure apps: ON ↓↓↓允许不太安全的应用程序:↓↓↓

    https://myaccount.google.com/lesssecureapps https://myaccount.google.com/lesssecureapps

  2. Allow access to your Google account: ON (Tap "Continue") ↓↓↓允许访问您的 Google 帐户:(点击“继续”)↓↓↓

    https://accounts.google.com/DisplayUnlockCaptcha https://accounts.google.com/DisplayUnlockCaptcha

    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
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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM