Gmail API返回403错误代码和“<用户电子邮件>的委派被拒绝”。

38

当检索邮件时,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应用程序范围委派来访问用户数据。域已授予应用程序数据访问权限。


1
这个错误也开始在我们这里出现了。到目前为止还没有任何问题。如果我们使用IMAP一切正常——看起来Gmail API存在一些问题。需要寻求Google的帮助吗? - PNC
1
你能否在请求中也附上“userId”字段所使用的值是什么?它是“me”,用户的电子邮件地址应该与 auth token 匹配,还是其他值? - Eric D
4
如果你使用的userId参数与授权用户不同,就会出现那个错误。不支持那种委派方式。正确的方法是在获取访问令牌时模拟用户,并坚持使用'me'作为userId。 - Steve Bazyl
3
在调用Gmail API时,只需使用userId="me"。对于具有域代理的服务帐户,您仅在请求访问令牌时为'sub'参数指定电子邮件地址。 - Eric D
好的,我会做 - 刚刚运行了请求,生成了错误。客户端ID数字是48629482。 - PNC
显示剩余9条评论
5个回答

80

看起来最好的做法就是在请求中始终使用userId="me"。这告诉API仅使用经过身份验证的用户邮箱,无需依赖电子邮件地址。


9
我更改了代码,使用“me”代替实际的电子邮件地址。问题是该电子邮件地址在我的实例中是别名所致。 - PNC
3
将电子邮件地址更改为“me”同样适用于我。谢谢。 - user1333358
8
@user1333358,你应该接受这个答案——它有效。 - koma
1
我为此挣扎了两个小时。这就是它! - wibberding
2
太棒了!我已经寻找了很长时间,而这个简单的解决方案就在这里。 - Umar
显示剩余4条评论

4

我之前也遇到过同样的问题,解决方案非常棘手。你需要先模拟要访问 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'])

或者你可以直接将其传递给 from_service_account_file(..., subject=email) - undefined

3
我们的用户已经迁移到一个域,并且他们的帐户附有别名。我们需要将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);


?>

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

您可以将其添加到程序末尾


0

最近我开始探索Gmail API,并且我正在遵循Guo提到的相同方法。然而,当我们有更多用户时,这将需要大量时间和太多的调用。在域范围委派之后,我的期望是管理员ID将能够访问被委派的收件箱,但似乎我们需要为每个用户创建服务。


3
这是一个答案吗?还是评论?请只在答案部分发布答案。 - Chris
你绝对不需要为每个用户提供一个服务。域范围委派应该可以解决问题,结合用户的primaryEmail而不是“我自己”。 - Air2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接