Google Apps Script :To set signature block for users automatically in a Google Apps Domain :


A signature block (often abbreviated as signature, sig block, sig file, .sig, dot sig, siggy, or just sig) is a block of text automatically appended at the bottom of an e-mail message. Information usually contained in a signature block includes the poster’s name, phone number and email address, along with other contact details if required, such as URLs for sites owned or favoured by the author.

We can set the signature manually in Setting -> General -> Signature in Goolge account. But if we want to set signature block Automatiically for users then we have to write some code.

Our requirement is that whenever a new user arrives, a script would run and set the default signature for that user and later user can change his signature by himself.

So for this, we will write a script at Admin account of a Google Apps Domain .

var organization="Your Organization"
var consumerkey="domainConsumerkey"
var consumerSecret="domainConsumerSecret"
var domainName="yourDomain.com"

function userSignature(){
  var email="yourEmail"
 setSignature(email) 
}
  
// Setting Signature
function setSignature(userEmail){
      var userName=userEmail.split("@")[0]

      // Creating Signature String for user
      var newUserSignatureString="First Name"+" " +"Last Name"+"<br>"
                               +organization+"<br>"+"Email"+"<br>";              
          
      var xml = '<?xml version="1.0" encoding="utf-8"?>' +
                '<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006" >' +
                '<apps:property name="signature" value="'+ newUserSignatureString+'" /></atom:entry>';
      
      var base="https://apps-apis.google.com/a/feeds/emailsettings/2.0/";
      var fetchArgs=googleOAuth_("google",base);
      fetchArgs.method="PUT"
      fetchArgs.contentType="application/atom+xml"
      fetchArgs.payload=xml
      
      var url = base + domainName + '/' + userName + '/signature';
      UrlFetchApp.fetch(url, fetchArgs);     // It sets the signature for new user
}


// Oauth Authentication
function googleOAuth_(name,scope) {
  var oAuthConfig = UrlFetchApp.addOAuthService(name)
  oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
  oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
  oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
  oAuthConfig.setConsumerKey(consumerkey);
  oAuthConfig.setConsumerSecret(consumerSecret);
  return {oAuthServiceName:name, oAuthUseToken:'always'};
} 

So after running this code, signature block of user will be set and user can view it here Setting -> General -> Signature.

About Rishi Khandelwal

Sr. Software Consultant having more than 6 years industry experience. He has working experience in various technologies such as Scala, Java, Play, Akka, Spark, Hive, Cassandra, Akka-http, ElasticSearch, Backbone.js, html5, javascript, Less, Amazon EC2, WebRTC, SBT
This entry was posted in Web and tagged . Bookmark the permalink.

22 Responses to Google Apps Script :To set signature block for users automatically in a Google Apps Domain :

  1. Mike says:

    Thank you for this! I’ve successfully implemented it into my Google Apps Script that I run when setting up new employees, and it will save me a lot of time.

    Quick tips for anyone who wants to use this with a signature that contains HTML code:
    In your newUserSignatureString variable:
    – Replace any with >
    – Replace any ” (double-quotes) with "

    Otherwise you will get a “Reference is not allowed in prolog” error.

    Also, if you’re adding this to a Google Apps Script that creates the user using this function:

    UserManager.createUser()

    …and then you want to set the signature next, make sure to include a 5-second pause:

    Utilities.sleep(5000);

    …after creating the user but before attempting to set the signature. Otherwise you will get an errorCode=”1410″ FeatureUnavailableForUser.

    You may be able to make it shorter than 5 seconds, but I did 5 just to be safe.

  2. Dennis Janssen says:

    How do I get the consumerkey and consumersecret? Can’t find it anywhere in the developers console and don’t see a way to create them.

  3. Alessio Fedi says:

    Hi, but this script work if Google close oAuth 1 ?? (April 2015)

  4. Nick says:

    Good evening Rishi,

    This script it fantastic and I’ve been using it for the last 2 years, however, as Alessio mentioned, it is no longer working as Google have deprecated oAuth. I would very much appreciate your assistance in updating this script to work with Google’s new authentication APIs?

  5. Mike says:

    Hey Nick and Alessio, it’s Mike from the first comment.

    I, also, was confused as to how to upgrade all my scripts from OAuth 1 to 2, so I feel obligated to post my working solution here…

    First, you need to follow the steps to add this library to your Apps Script project:

    https://github.com/googlesamples/apps-script-oauth2

    This can be a little confusing at first, so let me know if you have any problems with it. To save you some confusion, I’ve included my working adaptation of the code needed to use their library below. So pretty much all you have to do is:

    – Add the Library to your project
    – Get your OAUTH2_PROJECT_KEY, OAUTH2_CLIENT_SECRET, and OAUTH2_CLIENT_ID from the Google Developers console
    – Set them as constants in your project

    After you have that set up, you use their library to create an OAuth 2 service that is needed when calling the Email Settings API:

    function beginNewEmployeeProcedures() {

    var emailSettingsOauth2Service = createOauth2Service(‘Email Settings API’,’https://apps-apis.google.com/a/feeds/emailsettings/2.0/’,’authCallbackForEmailSettingsApi’);
    if (!emailSettingsOauth2Service.hasAccess()) { startOauth2AuthFlow(‘Email Settings API’,emailSettingsOauth2Service); return; }

    setSignature(emailSettingsOauth2Service,’test@yourgoogleappsdomain.com’,’cool email signature’);

    }

    function setSignature(service,email,signature) {

    try {

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

    var xml = ” +
    ” +
    ”;

    var fetchArgs = {};
    fetchArgs.headers = {‘Authorization’: ‘Bearer ‘+ service.getAccessToken()};
    fetchArgs.method = “PUT”;
    fetchArgs.contentType = “application/atom+xml”;
    fetchArgs.payload = xml;
    fetchArgs.muteHttpExceptions = true;

    var url = ‘https://apps-apis.google.com/a/feeds/emailsettings/2.0/yourgoogleappsdomain.com/’ + username + ‘/signature’;

    UrlFetchApp.fetch(url, fetchArgs);

    } catch(e) {

    // failure notification email, etc

    }

    }

    function createOauth2Service(serviceName,scope,callbackFunctionName) {

    // Create a new service with the given name. The name will be used when
    // persisting the authorized token, so ensure it is unique within the
    // scope of the property store.
    var service = OAuth2.createService(serviceName)

    // Set the endpoint URLs, which are the same for all Google services.
    .setAuthorizationBaseUrl(‘https://accounts.google.com/o/oauth2/auth’)
    .setTokenUrl(‘https://accounts.google.com/o/oauth2/token’)

    // Set the client ID and secret, from the Google Developers Console.
    .setClientId(OAUTH2_CLIENT_ID)
    .setClientSecret(OAUTH2_CLIENT_SECRET)

    // Set the project key of the script using this library.
    .setProjectKey(OAUTH2_PROJECT_KEY)

    // Set the name of the callback function in the script referenced
    // above that should be invoked to complete the OAuth flow.
    .setCallbackFunction(callbackFunctionName)

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

    // Set the scopes to request (space-separated for Google services).
    .setScope(scope)

    // Below are Google-specific OAuth2 parameters.

    // Sets the login hint, which will prevent the account chooser screen
    // from being shown to users logged in with multiple accounts.
    .setParam(‘login_hint’, Session.getActiveUser().getEmail())

    // Requests offline access.
    .setParam(‘access_type’, ‘offline’)

    // Forces the approval prompt every time. This is useful for testing,
    // but not desirable in a production application.
    .setParam(‘approval_prompt’, ‘force’);

    return service;

    }

    function startOauth2AuthFlow(serviceName,service) {

    var authorizationUrl = service.getAuthorizationUrl();

    var template = HtmlService.createTemplate(
    ‘<a href="” target=”_blank”>’+
    ‘Click here to authorize this script to access the ‘ + serviceName + ‘‘ +
    ‘After closing the other tab, click the X in this window and start the script again.’);

    template.authorizationUrl = authorizationUrl;

    var page = template.evaluate();

    SpreadsheetApp.getUi().showModalDialog(page, ‘API Authorization’);

    }

    function authCallbackForEmailSettingsApi(request) {

    // this script is called by the auth screen when the user clicks the blue Accept button

    var oauth2Service = createOauth2Service(‘Email Settings API’,’https://apps-apis.google.com/a/feeds/emailsettings/2.0/’,’authCallbackForEmailSettingsApi’);

    var isAuthorized = oauth2Service.handleCallback(request);

    if (isAuthorized) {
    return HtmlService.createHtmlOutput(‘Success! You can close this tab.’);
    } else {
    return HtmlService.createHtmlOutput(‘Didn\’t work.’);
    }

    }

    That’s it!

    Also, I just want to mention that I had to create authCallbackForEmailSettingsApi() specifically as the auth callback for this script, because the auth callback doesn’t seem to be able to send parameters or variables back to Apps Script, yet the auth callback needs to include the service name, scope, and callback function name in order to call createOauth2Service() again. If anyone knows of a way to get those values back from the server without needing a specific auth callback function, let me know! Then we could make a generic auth callback function and it could be re-used for different calls to different APIs.

  6. Mike says:

    Looks like my variable called xml in the setSignature() function got stripped out, so I reposted my code here in case you need it:

    http://stackoverflow.com/questions/30135119/how-to-use-the-google-email-settings-api-and-the-oauth2-for-apps-script-library/

    • Nick says:

      Hey Mike, thanks very much for your response and for the code from your project, I’m going to have a look through it this evening and give it a try!

  7. Derek says:

    @Mike Are you able to assist me with this. I’ve followed your instructions, I feel exactly, but cannot get my script to work. I’m stuck with the deprecated version. Would you be able to PM me? I would value your time, of course. Thank you,

  8. Danilo says:

    Mike and Nick, thank you very much for sharing this experience that is useful until this day. I had to use the standardized signatures feature in my business.
    I saw here that by July 2017, we’ll have to migrate to the Gmail API, as we can check in this site: https://developers.google.com/gmail/api/guides/migrate-from-email-settings
    Do you have any tips for doing this migration? Still looking for where to start! 🙂

    • Mike says:

      Hi Danilo,

      We figured out a great way to do this using the Gmail API and “Domain-wide Delegation”, which is a way for G Suite admins to make API calls on behalf of users within their domain. Basically, you need to “be” the user making the call to the API, so here’s how to do it automatically from a script as an admin without having to get the user themselves involved.

      Step 1: Make sure the OAuth2 For Apps Script (https://github.com/googlesamples/apps-script-oauth2) library is added to your project (details in previous post above).

      Step 2: Set up Domain-Wide Delegation. 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. Follow the steps for everything on this page up to and including the “Delegate domain-wide authority to your service account” step. (https://developers.google.com/drive/v2/web/delegation)

      Also, they may have updated the Google API Console and some of the steps in this documentation might not have been updated to match, but it’s not hard to figure out the new way to do it. Let me know if you have any trouble.

      Step 3: The code below includes how to set the signature, and also how to use the Domain-Wide Delegation service account.

      Please note: the whole do/while look with the maxSetSignatureAttempts and currentSetSignatureAttempts variables is not necessary. I added it because we set signatures immediately after creating the Google account and assigning the G Suite license, and sometimes the 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 20 times. You wouldn’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, and other times, it would still fail. So this loop is better than a fixed sleep amount.

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

      }

  9. Danilo says:

    MIke, Nick and Rishi, thank you very much for sharing this experience that is useful until this day. I had to use the standardized signatures feature in my business.
    I saw here that by July 2017, we’ll have to migrate to the Gmail API, as we can check in this site: https://developers.google.com/gmail/api/guides/migrate-from-email-settings
    Do you have any tips for doing this migration? Still looking for where to start! 🙂

    • Mike says:

      Hi Danilo,

      We figured out a great way to do this using the Gmail API and “Domain-wide Delegation”, which is a way for G Suite admins to make API calls on behalf of users within their domain. Basically, you need to “be” the user making the call to the API, so here’s how to do it automatically from a script.

      Step 1: Make sure the OAuth2 For Apps Script (https://github.com/googlesamples/apps-script-oauth2) library is added to your project (details in previous post above)

      Step 2: Set up Domain-Wide Delegation. 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. Follow the steps for everything on this page up to and including the “Delegate domain-wide authority to your service account” step. (https://developers.google.com/drive/v2/web/delegation)

      Also, they may have updated the Google API Console and some of the steps in this documentation might not have been updated to match, but it’s not hard to figure out the new way to do it. Let me know if you have any trouble.

      Step 3: The code below includes how to set the signature, and also how to use the Domain-Wide Delegation service account.

      Please note: the whole do/while look with the maxSetSignatureAttempts and currentSetSignatureAttempts variables is not necessary. I added it because we set signatures immediately after creating the Google account and assigning the G Suite license, and sometimes the 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 20 times. You wouldn’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, and other times, it would still fail. So this loop is better than a fixed sleep amount.

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

      }

    • Mike says:

      Hi Danilo,

      We figured out a great way to do this using the Gmail API and “Domain-wide Delegation”, which is a way for G Suite admins to make API calls on behalf of users within their domain. Basically, you need to “be” the user making the call to the API, so here’s how to do it automatically from a script.

      Step 1: Make sure the OAuth2 For Apps Script (https://github.com/googlesamples/apps-script-oauth2) library is added to your project (details in previous post above)

      Step 2: Set up Domain-Wide Delegation. 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. Follow the steps for everything on this page up to and including the “Delegate domain-wide authority to your service account” step. (https://developers.google.com/drive/v2/web/delegation)

      Also, they may have updated the Google API Console and some of the steps in this documentation might not have been updated to match, but it’s not hard to figure out the new way to do it. Let me know if you have any trouble.

      Step 3: The code below includes how to set the signature, and also how to use the Domain-Wide Delegation service account.

      Please note: the whole do/while look with the maxSetSignatureAttempts and currentSetSignatureAttempts variables is not necessary. I added it because we set signatures immediately after creating the Google account and assigning the G Suite license, and sometimes the 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 20 times. You wouldn’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, and other times, it would still fail. So this loop is better than a fixed sleep amount.

      function setSignatureTest() {

      var email = ‘test@test.com’;

      var signature = ‘test signature’;

      var test = setSignature(email, signature);

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

      }

      // continued in next comment…

  10. Mike says:

    I posted a reply but it’s not showing up. Maybe it’s too long… will try in 2 parts now.

  11. Mike says:

    Ok, I forgot, this blog comment system doesn’t let you post code. I’ve posted the answer here:

    http://stackoverflow.com/questions/40936257/how-to-use-the-gmail-api-oauth2-for-apps-script-and-domain-wide-delegation-to/40936258#40936258

    Please upvote my question and answer if it solves your problem! : )

    • Danilo says:

      I’m sorry for my absence. I’m going to see the code now and you’re sure to have my upvote. Thank you for your dedication.

    • Danilo says:

      It works perfectly well! Thank you so much Mike. I have no reputation for commenting on stackoverflow yet, but I’ve left an upvote for you there, and you deserve so much more than that!

      • Mike says:

        Awesome!

      • Mike says:

        Also, now that you’ve set up Domain-Wide Delegation of Authority, there’s so much more you can do as a G Suite admin with Apps Script. I’ve created an entire employee on-boarding/off-boarding process that involves hundreds of scripts, some of which use DWD to “impersonate” users when necessary for things like transferring ownership of Drive documents, creating and updating calendar events on another user’s behalf, and sending emails so they appear to come from a certain user. Just some inspiration for you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s