GmailAPI:"Error sending test message to Cloud PubSub projects/[project-id]/topics/[topic-id] : User not authorized to perform this action."?
GmailAPI: "Error sending test message to Cloud PubSub projects/[project-id]/topics/[topic-id] : User not authorized to perform this action."?
我正在使用 Gmail API,并尝试使用 Python 3.9 设置推送通知。当我尝试在我的 Gmail 收件箱上调用 watch() 时出现错误,尽管我已经遵循了针对类似问题给出的所有建议。错误内容为:
"Error sending test message to Cloud PubSub projects/[project-id]/topics/[topic-id] : User not authorized to perform this action."
到目前为止,我已经完成了以下工作:
- 创建主题
- 创建订阅
- 手动发送和接收消息
- 创建一个服务帐户,权限为“所有者”和“云 Pub/Sub 服务代理”
- 对于主题,将服务帐户设置为所有者
- 对于订阅,将服务帐户设置为所有者
在代码方面,我只是添加到 Google 提供的 Python 快速入门文件 (https://developers.google.com/gmail/api/quickstart/python) 中。这是我添加的内容:
from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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.json', 'w') as token:
token.write(creds.to_json())
#NEW CODE I ADDED FOR watch()
service = build('gmail', 'v1', credentials=creds)
request = {
'labelIds': ['INBOX'],
'topicName': 'projects/[project-id]/topics/[topic-id]'
}
service.users().watch(userId='me', body=request).execute()
if __name__ == '__main__':
main()
编辑:
- 我 运行 它在 Windows 笔记本电脑上,在 Visual Studio 代码中。我只是打开了一个新的 Python 文件。
- 这是一个@gmail.com 帐户,不是 GSuite 帐户
- 我正在使用服务帐户进行身份验证(creds 对象)
编辑 2:
我添加了带有上面凭据的完整文件。
更新答案
我已经测试了你的代码,我遇到了同样的问题,但这是因为我故意跳过步骤来弄清楚在某些阶段会发生什么。
当我未将服务帐户gmail-api-push@system.gserviceaccount.com
添加为相关主题的发布者时,我得到了你的确切问题。
请原谅我糟糕的绘画技巧:
原回答
所以问题是你正在尝试使用服务帐户来验证对 Gmail API 的 API 调用,我猜是 @gmail.com 帐户关注 this example.
唯一可行的方法是,如果您使用的帐户是 GSuite 帐户并且您使用的是域范围委派。 This doc(针对 Admin SDK,但其工作方式相同)解释了其工作原理。它不适用于您,但为了完整起见,我添加了它。
服务帐户不能用于验证@gmail.com帐户的请求。
它们可以用于验证自己的 GSuite 相关 APIs,例如 GDrive、GDocs 等,但它们基本上用于验证自己的帐户,绝不是@gmail.com 帐户。我不会对此进行详细说明,因为这并不完全相关,而且它有点奇怪,即使是爱丽丝也无法摆脱。
要通过您的@gmail.com 帐户使用 Gmail API,您需要按照快速入门 you linked so the request gets authenticated using the credentials for your @gmail.com account 中的指示创建 creds 对象。您只需执行一次,并将生成的 JSON 凭据文件保存在某处,以便您可以重复使用它。它会一直有效,直到您撤销它。
请注意 the docs 还声明您需要使用标准 Gmail API 身份验证。
下面的部分创建了 JSON 文件,您可以使用您登录时使用的@gmail.com 帐户对 Gmail API 的请求进行身份验证。
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
您可以使用此部分将凭据加载到 creds 对象中,然后只需使用您已有的代码就可以了...
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
我不是 100% 确定您是否需要授予 GCloud 项目本身的权限,但您可以通过完成快速入门的其余部分来测试 Gmail 信用对象是否工作,看看您是否可以获得标签对于@gmail.com 帐户。如果这有效,并且您仍然收到 403 错误,请尝试为 @gmail.com 帐户提供您授予服务帐户的 Pub/Sub IAM 权限。
我正在使用 Gmail API,并尝试使用 Python 3.9 设置推送通知。当我尝试在我的 Gmail 收件箱上调用 watch() 时出现错误,尽管我已经遵循了针对类似问题给出的所有建议。错误内容为:
"Error sending test message to Cloud PubSub projects/[project-id]/topics/[topic-id] : User not authorized to perform this action."
到目前为止,我已经完成了以下工作:
- 创建主题
- 创建订阅
- 手动发送和接收消息
- 创建一个服务帐户,权限为“所有者”和“云 Pub/Sub 服务代理”
- 对于主题,将服务帐户设置为所有者
- 对于订阅,将服务帐户设置为所有者
在代码方面,我只是添加到 Google 提供的 Python 快速入门文件 (https://developers.google.com/gmail/api/quickstart/python) 中。这是我添加的内容:
from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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.json', 'w') as token:
token.write(creds.to_json())
#NEW CODE I ADDED FOR watch()
service = build('gmail', 'v1', credentials=creds)
request = {
'labelIds': ['INBOX'],
'topicName': 'projects/[project-id]/topics/[topic-id]'
}
service.users().watch(userId='me', body=request).execute()
if __name__ == '__main__':
main()
编辑:
- 我 运行 它在 Windows 笔记本电脑上,在 Visual Studio 代码中。我只是打开了一个新的 Python 文件。
- 这是一个@gmail.com 帐户,不是 GSuite 帐户
- 我正在使用服务帐户进行身份验证(creds 对象)
编辑 2: 我添加了带有上面凭据的完整文件。
更新答案
我已经测试了你的代码,我遇到了同样的问题,但这是因为我故意跳过步骤来弄清楚在某些阶段会发生什么。
当我未将服务帐户gmail-api-push@system.gserviceaccount.com
添加为相关主题的发布者时,我得到了你的确切问题。
请原谅我糟糕的绘画技巧:
原回答
所以问题是你正在尝试使用服务帐户来验证对 Gmail API 的 API 调用,我猜是 @gmail.com 帐户关注 this example.
唯一可行的方法是,如果您使用的帐户是 GSuite 帐户并且您使用的是域范围委派。 This doc(针对 Admin SDK,但其工作方式相同)解释了其工作原理。它不适用于您,但为了完整起见,我添加了它。
服务帐户不能用于验证@gmail.com帐户的请求。
它们可以用于验证自己的 GSuite 相关 APIs,例如 GDrive、GDocs 等,但它们基本上用于验证自己的帐户,绝不是@gmail.com 帐户。我不会对此进行详细说明,因为这并不完全相关,而且它有点奇怪,即使是爱丽丝也无法摆脱。
要通过您的@gmail.com 帐户使用 Gmail API,您需要按照快速入门 you linked so the request gets authenticated using the credentials for your @gmail.com account 中的指示创建 creds 对象。您只需执行一次,并将生成的 JSON 凭据文件保存在某处,以便您可以重复使用它。它会一直有效,直到您撤销它。
请注意 the docs 还声明您需要使用标准 Gmail API 身份验证。
下面的部分创建了 JSON 文件,您可以使用您登录时使用的@gmail.com 帐户对 Gmail API 的请求进行身份验证。
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
您可以使用此部分将凭据加载到 creds 对象中,然后只需使用您已有的代码就可以了...
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
我不是 100% 确定您是否需要授予 GCloud 项目本身的权限,但您可以通过完成快速入门的其余部分来测试 Gmail 信用对象是否工作,看看您是否可以获得标签对于@gmail.com 帐户。如果这有效,并且您仍然收到 403 错误,请尝试为 @gmail.com 帐户提供您授予服务帐户的 Pub/Sub IAM 权限。