编辑:在接受答案之后:我的问题是关于一个免费的Gmail帐户(我不知道有什么区别(,答案是关于付费帐户(这是一个普通帐户(,答案告诉我有区别,这让我找到了正确的答案——使用密码
我试图使用谷歌API和服务帐户发送邮件,但我得到了以下错误:
An error occurred: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/me/drafts?alt=json returned "Precondition check failed.". Details: "[{'message': 'Precondition check failed.', 'domain': 'global', 'reason': 'failedPrecondition'}]">
这是我的代码:
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from oauth2client.service_account import ServiceAccountCredentials
import base64
from email.message import EmailMessage
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://mail.google.com/']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
creds = ServiceAccountCredentials.from_json_keyfile_name(
"""path_to_cred_file.json""", SCOPES)
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
message = EmailMessage()
message.set_content('This is automated draft mail')
message['To'] = 'somemail@gmail.com'
message['From'] = 'somemail@gmail.com'
message['Subject'] = 'Automated draft'
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {
'message': {
'raw': encoded_message
}
}
# pylint: disable=E1101
draft = service.users().drafts().create(userId="me",
body=create_message).execute()
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
"先决条件检查失败";通常意味着你试图做一些不能做的事情。在这种情况下,您试图从服务帐户发送电子邮件,这是不可能的。这个答案有一个链接,链接到谷歌文档中的一个相关线程。他们说:
除非您设置了Gsuite帐户的域范围委派,否则服务帐户无法使用gmail。原因是服务帐户是它自己的用户,你需要委托它访问你的gmail帐户的权限。这只适用于gsuite域电子邮件地址。
这意味着服务帐户本身不能发送消息,而是需要被授权访问常规用户帐户才能发送电子邮件。为此,您可以在creds
:之后添加以下行
delegated_creds=credentials.with_subject("someuser@yourdomain.com")
#where someuser@ is the email of the user that you're sending email as
之后,您可以使用delegated_creds
而不是creds
来调用该服务。
此外,你似乎从谷歌的指南中获得了你的样本,但请注意,你的样本创建了一个草稿,而不是发送电子邮件。发送电子邮件的API调用有点不同。考虑到这一点,这里有一个基于您的代码的完整示例,对我有效:
#all the imports
SCOPES = ['https://mail.google.com/']
def main():
creds = None
creds = ServiceAccountCredentials.from_json_keyfile_name(
"""path_to_cred_file.json""", SCOPES)
delegated_creds=credentials.with_subject("someuser@yourdomain.com")
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=delegated_creds)
message = EmailMessage()
message.set_content('This is automated draft mail')
message['To'] = 'somemail@gmail.com'
message['From'] = 'somemail@gmail.com'
message['Subject'] = 'Automated draft'
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {
'raw': encoded_message
}
email = service.users().messages().send(userId="me",
body=create_message).execute()
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
最后,正如我链接的帖子中所解释的,这只适用于谷歌工作区账户,你不能授权访问免费的Gmail账户,所以请记住这一点。