如何在不启用“不安全访问”的情况下通过gmail发送电子邮件?

2024-04-19 01:06:44 发布

您现在位置:Python中文网/ 问答频道 /正文

谷歌正在推动我们提高gmail smtp服务器脚本访问的安全性。我没意见。事实上我很乐意帮忙。

但他们不容易做到。建议我们Upgrade to a more secure app that uses the most up to date security measures是很好的,但这并不能帮助我解决如何升级如下代码的问题:

server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(GMAIL_USER, GMAIL_PASSWORD)
server.sendmail(FROM, TO, MESSAGE)
server.close()

当然,我会打开“访问不太安全的应用程序”,但如果有人想出了用什么来替换这段代码,我将不胜感激。


Tags: to代码服务器脚本appservermoresmtp
3条回答

这很痛苦,但我现在好像有点事。。。

还不支持Python3

我不认为这太难实现,因为我在转换包时遇到了障碍,没有碰到任何大的问题:只有通常的2to3东西。但几个小时后,我厌倦了逆流而上游泳。在撰写本文时,我找不到Python 3的公开使用包。python 2的体验是直截了当的(相比之下)。

浏览谷歌网站是成功的一半

毫无疑问,随着时间的推移,这种情况将会改变。最终,您需要下载一个client_secret.json文件。您只能(可能)通过web浏览器进行设置:

  1. 你需要一个谷歌帐户-要么谷歌应用程序或gmail。所以,如果你没有,去买一个。
  2. developers console
  3. 创建一个新项目,并等待4或400秒才能完成。
  4. 导航到API's and Auth->;Credentials
  5. OAuth下选择Create New Client ID
  6. 选择Installed Application作为应用程序类型,选择其他
  7. 现在应该有一个按钮Download JSON。做那件事。这是你的client_secret.json-可以说是密码

但等等,还不止这些!

你必须给你的申请一个“产品名”,以避免一些奇怪的错误。(看看我为给你这个付出了多少;-)

  1. 导航到API's & auth->;Consent Screen
  2. 选择您的电子邮件
  3. 输入产品名称。不管是什么。”Foobar“会很好的。
  4. 保存

新闻快报!哇哦。现在还有更多!

  1. 导航到API的&;身份验证->;API->;Gmail API
  2. 单击“启用API”按钮

是的。现在我们可以更新电子邮件脚本。

Python2

您需要在第一次以交互方式运行脚本。它将在您的计算机上打开一个web浏览器,您将授予权限(单击按钮)。此练习将向您的计算机保存一个包含可重用令牌的文件gmail.storage

[我没有运气将令牌转移到没有图形浏览器功能的机器上返回HTTPError。我试着通过lynx图形浏览器来浏览。这也失败了,因为谷歌已经将最后的“接受”按钮设置为“禁用”!?我会提出另一个问题来跳过这个障碍(更多的抱怨)]

首先,您需要一些库:

pip install --upgrade google-api-python-client
pip install --upgrade python-gflags
  • 您需要更改往返地址
  • 确保您拥有客户机令牌.json文件,只要Storage指令要求它
  • 目录需要是可写的,这样它才能保存gmail.storage文件

最后是一些代码:

import base64
import httplib2

from email.mime.text import MIMEText

from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run


# Path to the client_secret.json file downloaded from the Developer Console
CLIENT_SECRET_FILE = 'client_secret.json'

# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.compose'

# Location of the credentials storage file
STORAGE = Storage('gmail.storage')

# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()

# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
  credentials = run(flow, STORAGE, http=http)

# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)

# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)

# create a message to send
message = MIMEText("Message goes here.")
message['to'] = "yourvictim@goes.here"
message['from'] = "you@go.here"
message['subject'] = "your subject goes here"
body = {'raw': base64.b64encode(message.as_string())}

# send it
try:
  message = (gmail_service.users().messages().send(userId="me", body=body).execute())
  print('Message Id: %s' % message['id'])
  print(message)
except Exception as error:
  print('An error occurred: %s' % error)

希望这能让我们都开始。不像以前那样简单,但现在看起来确实不那么复杂了,我可以从肉体上看出来。

你考虑过使用Gmail API吗?该API具有内置的安全特性,并专门针对Gmail进行了优化。可以在http://developers.google.com上找到API文档-例如,下面是Send API调用的文档:

https://developers.google.com/gmail/api/v1/reference/users/messages/send

约翰·米的回答似乎过时了。 2016年7月不起作用。 可能是因为Gmail的API更新。 我更新了他的代码(python 2),如下所示:

    """Send an email message from the user's account.
"""

import base64
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
import os

#from __future__ import print_function
import httplib2
import os

from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools

from apiclient import errors

SCOPES = 'https://www.googleapis.com/auth/gmail.compose'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Gmail API Python Quickstart'

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None

def SendMessage(service, user_id, message):
  """Send an email message.

  Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    message: Message to be sent.

  Returns:
    Sent 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 CreateMessage(sender, to, subject, message_text):
  """Create a message for an email.

  Args:
    sender: Email address of the sender.
    to: Email address of the receiver.
    subject: The subject of the email message.
    message_text: The text of the email message.

  Returns:
    An object containing a base64url encoded email object.
  """
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject
  return {'raw': base64.urlsafe_b64encode(message.as_string())}


def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'sendEmail.json')

    store = oauth2client.file.Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials

if __name__ == "__main__":

    try:
        credentials = get_credentials()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        SendMessage(service, "me", CreateMessage("send@gmail.com", "receive@gmail.com", "Test gmail automation", "Hello world"))

    except Exception, e:
        print e
        raise

注意,如果遇到错误Insufficient Permission,一个可能的原因是程序中的范围设置不正确。 另一个可能的原因可能是您需要删除存储json文件(“sendmail.json”在此程序中)并刷新您的程序。更多的细节可以在这个post中看到。

相关问题 更多 >