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

Solution 1:

This method uses the Gmail API, the OAuth2 for Apps Script library, and "Domain-wide Delegation of Authority", which is a way for G Suite admins to make API calls on behalf of users within their domain.

Step 1: Make sure the OAuth2 For Apps Script library is added to your project.

Step 2: Set up "Domain-Wide Delegation of Authority." There's a page here explaining how to do it for the Drive API, but it's pretty much the same for any Google API, including the Gmail API. Follow the steps on that page up to, and including, the "Delegate domain-wide authority to your service account" step.

Step 3: The code below includes how to set the signature after the previous steps are complete:

function setSignatureTest() {

  var email = '[email protected]';

  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);

}

Please note: the do-while loop with the maxSetSignatureAttempts and currentSetSignatureAttempts variables is not necessary. I added it because if you're trying to set signatures immediately after creating the Google account and assigning a G Suite license, sometimes the Gmail API returns an error as if the user wasn't created yet. That do-while loop basically waits 3 seconds if it gets an error, then tries again, up to x number of times. You shouldn't have that issue if you're setting signatures for existing users. Also, originally I just had a fixed 10-second sleep, but most of the time it didn't need to take that long, but other times it would still fail. So this loop is better than a fixed sleep amount.