如何使用 Gmail API、OAuth2 for Apps 脚本和域范围委派为 G Suite 域中的用户设置电子邮件签名

Posted

技术标签:

【中文标题】如何使用 Gmail API、OAuth2 for Apps 脚本和域范围委派为 G Suite 域中的用户设置电子邮件签名【英文标题】:How to use the Gmail API, OAuth2 for Apps Script, and Domain-Wide Delegation to set email signatures for users in a G Suite domain 【发布时间】:2017-04-17 14:28:39 【问题描述】:

这是我之前发布的问题/答案 (How to use the Google Email Settings API and the OAuth2 for Apps Script Library to set email signatures for users in a Google Apps domain) 的后续,但我正在创建一个新问题,因为 Email Settings API 已被弃用,并且现在该过程有很大不同。

作为 G Suite 域的管理员,您如何使用 Gmail API 通过 Google Apps 脚本以编程方式设置域中用户的电子邮件签名?

【问题讨论】:

【参考方案1】:

此方法使用 Gmail API、OAuth2 for Apps 脚本库和“域范围的授权”,这是 G Suite 管理员代表其域内的用户进行 API 调用的一种方式。

第 1 步:确保将 OAuth2 For Apps Script 库添加到您的项目中。

第 2 步: 设置“域范围的授权”。有一个页面here 解释了如何为 Drive API 执行此操作,但对于任何 Google API(包括 Gmail API)来说几乎都是一样的。按照该页面上的步骤直至(包括)“将域范围的权限委派给您的服务帐户”步骤。

第三步:下面的代码包含了在前面的步骤完成后如何设置签名:

function setSignatureTest() 

  var email = 'test@test.com';

  var signature = 'test signature';

  var test = setSignature(email, signature);

  Logger.log('test result: ' + test);




function setSignature(email, signature) 

  Logger.log('starting setSignature');

  var signatureSetSuccessfully = false;

  var service = getDomainWideDelegationService('Gmail: ', 'https://www.googleapis.com/auth/gmail.settings.basic', email);

  if (!service.hasAccess()) 

    Logger.log('failed to authenticate as user ' + email);

    Logger.log(service.getLastError());

    signatureSetSuccessfully = service.getLastError();

    return signatureSetSuccessfully;

   else Logger.log('successfully authenticated as user ' + email);

  var username = email.split("@")[0];

  var resource =  signature: signature ;

  var requestBody                = ;
  requestBody.headers            = 'Authorization': 'Bearer ' + service.getAccessToken();
  requestBody.contentType        = "application/json";
  requestBody.method             = "PUT";
  requestBody.payload            = JSON.stringify(resource);
  requestBody.muteHttpExceptions = false;

  var emailForUrl = encodeURIComponent(email);

  var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs/' + emailForUrl;

  var maxSetSignatureAttempts     = 20;
  var currentSetSignatureAttempts = 0;

  do 

    try 

      currentSetSignatureAttempts++;

      Logger.log('currentSetSignatureAttempts: ' + currentSetSignatureAttempts);

      var setSignatureResponse = UrlFetchApp.fetch(url, requestBody);

      Logger.log('setSignatureResponse on successful attempt:' + setSignatureResponse);

      signatureSetSuccessfully = true;

      break;

     catch(e) 

      Logger.log('set signature failed attempt, waiting 3 seconds and re-trying');

      Utilities.sleep(3000);

    

    if (currentSetSignatureAttempts >= maxSetSignatureAttempts) 

      Logger.log('exceeded ' + maxSetSignatureAttempts + ' set signature attempts, deleting user and ending script');

      throw new Error('Something went wrong when setting their email signature.');

    

   while (!signatureSetSuccessfully);

  return signatureSetSuccessfully;



// these two things are included in the .JSON file that you download when creating the service account and service account key
var OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY  = '-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n';
var OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = 'xxxxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com';


function getDomainWideDelegationService(serviceName, scope, email) 

  Logger.log('starting getDomainWideDelegationService for email: ' + email);

  return OAuth2.createService(serviceName + email)
      // Set the endpoint URL.
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the private key and issuer.
      .setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY)
      .setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL)

      // Set the name of the user to impersonate. This will only work for
      // Google Apps for Work/EDU accounts whose admin has setup domain-wide
      // delegation:
      // https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
      .setSubject(email)

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getScriptProperties())

      // Set the scope. This must match one of the scopes configured during the
      // setup of domain-wide delegation.
      .setScope(scope);


请注意:带有maxSetSignatureAttemptscurrentSetSignatureAttempts 变量的do-while 循环不是必需的。我添加它是因为如果您在创建 Google 帐户并分配 G Suite 许可证后立即尝试设置签名,有时 Gmail API 会返回错误,就好像尚未创建用户一样。如果出现错误,该 do-while 循环基本上会等待 3 秒,然后再试一次,最多 x 次。如果您为现有用户设置签名,则不应该有这个问题。另外,本来我只是固定的 10 秒睡眠,但大多数时候它不需要花那么长时间,但其他时候它仍然会失败。所以这个循环比固定的睡眠量要好。

【讨论】:

您好,如果不是 G Suite 域的管理员,可以这样做吗?我只想登录我的 gmail 帐户来发出 http 请求... 不,您不能这样做,因为“域范围的委派”专门针对 G Suite 管理员。但是,如果您只是想设置自己的电子邮件签名,那么您应该可以在没有 DWD 的情况下完成。去掉对getDomainWideDelegationService 的调用和第一个if 语句,将service.getAccessToken() 更改为ScriptApp.getOAuthToken()。那应该为您自己的帐户获得一个有效的令牌。让我知道这是否有效。 嗨,迈克,我尝试了上面的代码,它可以工作。但是,当我使用 Gmail.Users.Settings.SendAs.patch() 方法而不是 HTTP 请求和 UrlFetchApp 来更新域中其他用户的签名时,我很困惑为什么会出现“GoogleJsonResponseException:未找到”错误。对于域范围的委派、服务帐户和 OAuth 相关任务,我是否只允许使用使用 UrlFetchApp 服务的 Gmail REST 接口而不是 Gmail API 服务方法进行调用? 是的,在 Apps 脚本编辑器 (GmailApp) 中使用 Gmail 服务时,您只能作为活动/有效用户(运行脚本的用户,从编辑器内或从定时触发)。具有域范围委派的服务帐户允许您作为管理员代表域中的其他帐户进行 API 调用,但这需要使用 Gmail REST API,并且它不适用于内置的 GmailApp 服务。 迈克,我指的是 Gmail API(在 Advance Google 服务中)而不是 GmailApp(在 G Suite 服务中)。根据 Gmail API 参考,您可以使用此处记录的 Gmail.Users.Settings.SendAs.patch() 方法:developers.google.com/gmail/api/v1/reference/users/settings/… 我已经尝试使用帐户服务使用此方法,但它不起作用。请在此处查看我的详细问题:***.com/questions/49784910/… 感谢您的回复。

以上是关于如何使用 Gmail API、OAuth2 for Apps 脚本和域范围委派为 G Suite 域中的用户设置电子邮件签名的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 gmail api 使用 nodemailer smtp oauth2?收到错误 535:不接受用户和通行证

通过服务器端的服务帐户使用 gmail api,避免使用 OAUTH2 GUI

Gmail API - Oauth2/google:找不到凭据(Golang)

谷歌 gmail api oauth2 身份验证错过了解

如何使用新的 Gmail REST API 成功发送消息?

如何使用 Twisted 通过 OAuth2.0 身份验证检查 Gmail