GoogleJsonResponseException: Not Found error when

2019-08-27 21:09发布

问题:

I want to update signature of a domain user via Google Apps Script as G Suite administrator.

I followed Mike's example here using HTTP Request to the Gmail API and was able to it to work.

Here is the summary what I did:

  • Enabled Gmail API in Advance Google Services and in Google API Console

  • Added OAuth2 for Apps Script library to my project (since Apps Script doesn't provide built-in support for OAuth2 protocol)

  • Created a Service Account for my project

  • Delegated domain-wide authority to the Service Account

  • Added "https://www.googleapis.com/auth/gmail.settings.sharing" scope

The following code works GREAT (see original version here)

function setSignatureWithHTTPRequest(email, signature) {
  var signatureSetSuccessfully = false;
  var authorizationScope = ['https://www.googleapis.com/auth/gmail.settings.sharing'];
  
  var service = getDomainWideDelegationService("Gmail: ", authorizationScope, 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;

  try {
    var setSignatureResponse = UrlFetchApp.fetch(url, requestBody);
    signatureSetSuccessfully = true;
    Logger.log("setSignatureResponse on successful attempt:" + setSignatureResponse);
  } catch (e) {
    Logger.log("Set signature with HTTP request failed: " + e);
  }
  
  return signatureSetSuccessfully;
}

However, when I modify the code to use the patch method from the Gmail API instead of HTTP Request with UrlFetchApp, I get a GoogleJsonResponseException: Not Found error.

function setSignatureWithMethod(email, signature) {
  var signatureSetSuccessfully = false;
  var authorizationScope = ['https://www.googleapis.com/auth/gmail.settings.sharing'];
  
  var service = getDomainWideDelegationService("Gmail: ", authorizationScope, 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 resource = { signature: signature };
  
  try {
    var setSignatureResponse = Gmail.Users.Settings.SendAs.patch(resource, "me", email);
    Logger.log("setSignatureResponse on successful attempt:" + setSignatureResponse);
    signatureSetSuccessfully = true;
  } catch (e) {
    Logger.log("Set signature with method failed: " + e);
  }

  return signatureSetSuccessfully;
}

My question is twofold.

  • Why function setSignatureWithMethod() generates error?

  • Another poster mentioned here that "...you will need to use the Gmail REST interface using UrlFetchApp service to make the calls instead of the Gmail service...because scripts can not run as a service account, only a user account." Is this accurate? Are the methods provided by the Gmail API (list, patch, update, etc.) are only for setting your own email signature (or own Gmail settings) and not for other user in the domain?

回答1:

Ok, two things.

1 - Gmail.Users.Settings.SendAs.patch() won't work. I think that's either an example of how the Gmail API would be implemented in any language, or it's part of a Java library provided by Google which can't be used in Apps Script.

Try changing this line:

var setSignatureResponse = Gmail.Users.Settings.SendAs.patch(resource, "me", email);

to this block:

var requestBody                = {};
requestBody.headers            = {"Authorization": "Bearer " + service.getAccessToken()};
requestBody.contentType        = "application/json";
requestBody.method             = "PATCH";
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;

try {

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

  signatureSetSuccessfully = true;

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

} catch (e) {

  Logger.log("Set signature with HTTP request failed: " + e.message);

}

2 - Not sure if this matters but you're sending an array as the authorization scope, but my original example and all my working code uses a string.

Try changing this:

var authorizationScope = ['https://www.googleapis.com/auth/gmail.settings.sharing'];

to this...

var authorizationScope = 'https://www.googleapis.com/auth/gmail.settings.sharing';