Gmail API 返回 403 错误代码和“<user email> 的委托被拒绝”

Posted

技术标签:

【中文标题】Gmail API 返回 403 错误代码和“<user email> 的委托被拒绝”【英文标题】:Gmail API returns 403 error code and "Delegation denied for <user email>" 【发布时间】:2014-11-25 22:28:09 【问题描述】:

在检索出现此错误的邮件时,一个域的 Gmail API 失败:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 OK

  "code" : 403,
  "errors" : [ 
    "domain" : "global",
    "message" : "Delegation denied for <user email>",
    "reason" : "forbidden"
   ],
  "message" : "Delegation denied for <user email>"

我正在使用 OAuth 2.0 和 Google Apps 域范围授权来访问用户数据。域已授予应用程序的数据访问权限。

【问题讨论】:

我们也开始出现此错误。迄今为止没有任何问题。如果我们使用 IMAP 一切都很好 - 看起来 Gmail API 有一些问题。谷歌帮助?? 这之前是否有效或刚刚中断?如果它刚刚坏了,你能给出它坏的时间吗?如果它从未起作用,您能否确认它是一个服务帐户,在 Cpanel 中列入白名单并提供有关域范围设置的更多详细信息?您正在使用类似:developers.google.com/accounts/docs/… 我想? 您还可以发布您在请求中为“userId”字段使用的值吗?是“我”,应该与身份验证令牌匹配的用户电子邮件地址还是其他? 只有当您使用不同于授权用户的 userId 参数时才会出现该错误。不支持这种委托方式。正确的方法是在获取访问令牌时冒充用户并坚持使用'me'作为userId。 只需在调用 Gmail API 时使用:userId="me"。对于具有域范围委派的服务帐户,您指定电子邮件地址的唯一时间是在请求访问令牌时用于“sub”参数。 【参考方案1】:

似乎最好的办法就是在您的请求中始终包含 userId="me" 。这告诉 API 只使用经过身份验证的用户的邮箱——无需依赖电子邮件地址。

【讨论】:

我将代码更改为使用“我”而不是实际的电子邮件地址。问题是由于电子邮件地址在我的实例中是别名造成的。 将电子邮件地址更改为“我”也对我有用。谢谢。 @user1333358 你应该接受答案 - 它有效 我为此苦苦挣扎了两个小时。就是这个! 太棒了!找了这么久,有了这个简单的解决方案。【参考方案2】:

我们的用户已迁移到某个域,并且他们的帐户附加了别名。我们需要将 SendAs 地址默认为一个导入的别名,并希望有一种方法来自动化它。 Gmail API 看起来像是解决方案,但我们具有更改帐户角色的特权用户无法正常工作 - 我们一直看到“Delegation denied for” 403 错误。

这是一个 php 示例,说明我们如何能够列出他们的 SendAs 设置。

<?PHP

//
// Description:
//   List the user's SendAs addresses.
//
// Documentation:
//   https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs
//   https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs/list
//
// Local Path:
//   /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail.php
//   /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail/Resource/UsersSettingsSendAs.php
//
// Version:
//    Google_Client::LIBVER  == 2.1.1
//

require_once $API_PATH . '/path/to/google-api-php-client/vendor/autoload.php';

date_default_timezone_set('America/Los_Angeles');

// this is the service account json file used to make api calls within our domain
$serviceAccount = '/path/to/service-account-with-domain-wide-delagation.json';
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $serviceAccount );

$userKey = 'someuser@my.domain';

// In the Admin Directory API, we may do things like create accounts with 
// an account having roles to make changes. With the Gmail API, we cannot 
// use those accounts to make changes. Instead, we impersonate
// the user to manage their account.

$impersonateUser = $userKey;

// these are the scope(s) used.
define('SCOPES', implode(' ', array( Google_Service_Gmail::GMAIL_SETTINGS_BASIC ) ) );

$client = new Google_Client();
$client->useApplicationDefaultCredentials();  // loads whats in that json service account file.
$client->setScopes(SCOPES); // adds the scopes
$client->setSubject($impersonateUser);  // account authorized to perform operation

$gmailObj  = new Google_Service_Gmail($client);

$res       = $gmailObj->users_settings_sendAs->listUsersSettingsSendAs($userKey);

print_r($res);


?>

【讨论】:

【参考方案3】:

我之前也遇到过同样的问题,解决方案非常棘手,您需要先冒充您需要访问 gmail 内容的人,然后使用 userId='me' 运行查询。它对我有用。

这里是一些示例代码:

   users = # coming from directory service
   for user in users:
     credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)
     ####IMPORTANT######
     credentials_delegated = credentials.with_subject(user['primaryEmail'])

     gmail_service = build('gmail', 'v1', credentials=credentials_delegated)

     results = gmail_service.users().labels().list(userId='me').execute()
     labels = results.get('labels', [])
       for label in labels:
          print(label['name'])

【讨论】:

【参考方案4】:

我想访问新电子邮件 ID/帐户的电子邮件,但发生的情况是,最近创建的包含 JSON 的“.credentials”文件夹与我之前尝试的先前电子邮件 ID/帐户相关联。 JSON 中存在的访问令牌和其他参数与新的电子邮件 ID/帐户无关。因此,为了使其运行,您只需删除“.credentails”文件夹并再次运行程序。现在,程序会打开浏览器并要求您授予权限。

在python中删除包含文件的文件夹

import shutil
shutil.rmtree("path of the folder to be deleted")

你可以在程序末尾添加这个

【讨论】:

【参考方案5】:

最近我开始探索 Gmail API,我采用的方法与郭提到的相同。但是,当我们的用户数量或更多时,它会花费时间和太多的电话。在域范围委派之后,我的期望是管理员 ID 将能够访问委派的收件箱,但似乎我们需要为每个用户创建服务。

【讨论】:

这是一个答案吗?还是评论?请仅在答案部分发布答案。

以上是关于Gmail API 返回 403 错误代码和“<user email> 的委托被拒绝”的主要内容,如果未能解决你的问题,请参考以下文章

在 c# 中使用 gmail API 修改消息标签时权限不足 [403] 错误

错误 403,元数据范围不允许格式 FULL 。 Web 应用程序 Gmail API 通过邮递员获取消息

调用 GMAIL API 时出现间歇性错误 - “调用者没有权限”

使用 api 密钥使用 Web API 时,出现以下错误 - 远程服务器返回错误:(403) Forbidden

Google Youtube API 插入评论总是返回错误响应 403-“权限不足”-域“全局”

带有gmail api的node js,API返回错误:错误:未授权客户端