If you’re like me, you are an admin looking at how you can use the Gmail API to update signatures of gsuite users, using server side authorization to save all the fuss of OAuth prompts. The goal is to simply have your server talk to and be able to update gsuite users (gmail signatures in particular). If you know a little bit of PHP, then this will be very easy for most admins to follow. This solution is great if you are an admin and want everyone to have a standard email signature.
Download GSuite Manager for PHP
Setup the gmail API
For this first part of the process we want to setup a new project or enable the gmail API for an already existing project. After this has been done we will create a service account which will be delegated to access parts of your GSuite account. You can think of this service account as just another admin user with rights to modify certain resources on your GSuite account.
- Follow the getting started guide through the link here to create a new project, service account and key.
Create a new project and enable to API
Create a new Service Account and download the JSON file
Once you click ‘Continue’, the JSON Key file will automatically download. Store this in a safe place and NEVER share this file with anyone.
Enable GSuite OAuth/Domain Wide Delegation
Make a copy of your “Client ID”
Your client ID will be used in the next step and added into your GSuite Security Settings.
Grant Domain-Wide Delegation (GSuite)
Now that you have your client ID, you can browse into the Security settings (You must be a GSuite Admin) and add in your client ID and the following scopes.
- SCOPE 1: https://www.googleapis.com/auth/gmail.settings.basic
- SCOPE 2: https://www.googleapis.com/auth/gmail.settings.sharing
Both of these scopes are used to set the Signature (and other settings). If you want additional scopes you can check out and enable the ones you need in the Gmail Reference Guide.
Copy paste in your client ID and the two scopes
1 |
https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/gmail.settings.sharing |
That’s the hardest part done. After completing this step you will now have a service account which can talk to the Gmail API
Get/Update Signature in PHP
If you don’t want to use PHP, then Google offers libraries for most of the popular languages.
If you’re already familiar with PHP, you can also follow the very easy guide on the Gmail API page to import the library and start making your own calls.
Otherwise, you can follow the below to utilize the basic commands of the Gmail library.
Set all your variables
Copy your service-account.json file which you downloaded earlier into a folder that is accessible by your local web server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//This is the primary email of the person whos' signature you want to update //Copy of your service-account.json file which includes the key for authentication putenv('GOOGLE_APPLICATION_CREDENTIALS=service-account.json'); //Instantiates the Google client class with the scopes and variables to update the signature $client = new Google_Client(); $client->useApplicationDefaultCredentials(); $client->setScopes(array('https://www.googleapis.com/auth/gmail.settings.basic','https://www.googleapis.com/auth/gmail.settings.sharing')); $client->setSubject($user_to_impersonate); //Instantiates the Gmail services class with the client information $gmail = new Google_Service_Gmail($client); |
PATCH (update) a users signature
1 2 3 4 5 6 7 8 9 |
//Set the HTML for your new signature $newSignature = "Enter your HTML here" // Instantiate the Gmail SendAs class and set the signature value $signature = new Google_Service_Gmail_SendAs(); $signature->setSignature($newSignature); //Send the request to update the signature $response = $gmail->users_settings_sendAs->patch("[email protected]","[email protected]",$signature); |
GET a users signature
1 2 3 4 5 6 |
//The users_settings function takes two variables - the primary email address and the alias. $response = $gmail->users_settings_sendAs->get("[email protected]","[email protected]")->getSignature(); //Just for if you want to output to test json_encode($response); var_dump($response); |
Thanks so much for this step-by-step. The instructions in Google’s documentation leave much to be desired as far as helping someone who’s not a hardcore developer to navigate this process.
Something not mentioned in your procedure above, but which is part of the setup, is the download of the Google API client, and the inclusion of a “require_once” reference in the PHP code.
Also, I initially got a cURL error about SSL certificates when I first ran your code. A little research revealed that I needed to download an updated cacert.pem file (from https://curl.haxx.se/docs/caextract.html) and reference it in my php.ini file (I saw a thread with a couple of different options as to how to reference it — one as openssl.cafile and one as curl.cainfo — so I used both).
Another note: Once you “patch” someone’s signature, the end-user will need either to refresh the GMail view in his/her browser, or otherwise log out/in for the change to take effect.
Hi Vince,
Thanks for your feedback – I had included a link to the Google PHP page which outlines how to install using composer. I did originally leave this out as everyone has their own way of installing and managing packages for a project. Bit of an assumption that you already know how to get the package installed 🙂
If you’re looking for something a bit easier, I’ve created a library which helps in the whole process – Download on Github
For the SSL certificate, this was something that worked by default when I was testing. But thank you for adding your comments in case anyone else comes across the same issue.
Best,
MooMaster
Thanks for this doing this.
I have your library installed and all the credentials in place. Including the domain-wide delegation. But when I execute: php index.php, I get this message.
Fatal error: Uncaught Google_Service_Exception: {
“error”: “unauthorized_client”,
“error_description”: “Client is unauthorized to retrieve access tokens using this method.”
}
in /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Http/REST.php:118
Stack trace:
#0 /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Http/REST.php(94): Google_Http_REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#1 /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Task/Runner.php(176): Google_Http_REST::doExecute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#2 /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Http/REST.php(58): Google_Task_Runner->run()
#3 /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Client.php(788): Google_Http_REST::execute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’, Array)
#4 / in /Applications/AMPPS/www/tests/gmail/vendor/google/apiclient/src/Google/Http/REST.php on line 118
I might be missing something simple but I’m not sure.
Hi Danny,
Two things I would check.
1. Make sure that your service account has domain wide delegation. As per the instructions above.
2. Make sure the following scopes are set.
Should look something like the below.
Feel free to also send a quick copy of what you have in the index.php file to help debug what else might be going wrong. Also don’t forget to update the index.php file with your own domain settings (otherwise it will use default vaules)
Best,
MooMaster
Hey Moo Master,
Thanks for the help. I went through and checked all the setting above step by step. All is set up there.
With the index.php file im using now I get :
Fatal error: Uncaught Error: Call to a member function setSubject() on null in /Applications/AMPPS/www/tests/gmail/vendor/moometric/gsuite/src/mooSignature.php:82 Stack trace: #0 /Applications/AMPPS/www/tests/gmail/vendor/moometric/gsuite/src/mooSignature.php(171): Moometric\mooSignature->getUsersList() #1 /Applications/AMPPS/www/tests/gmail/index.php(30): Moometric\mooSignature->updateSignatures() #2 {main} thrown in /Applications/AMPPS/www/tests/gmail/vendor/moometric/gsuite/src/mooSignature.php on line 82
my index.php right now is:
addSettingRunTestMode(True);
$mooSig->addSettingPreviewSignature(True);
// OPTIONAL – Setting the service account path and signature path if not using default location
//$mooSig->addSettingServiceAccountPath($serviceAccountPath);
//$mooSig->addsettingSignaturePath($sigPath);
// Setting test and preview mode so no changes are written
$mooSig->addSettingRunTestMode(True);
$mooSig->addSettingPreviewSignature(True);
// Setting the default signature
$mooSig->addSettingSetTemplate(“defaultSig.html”);
echo “Updating a single user from domain”;
// Example 1: setting a single user from domain
$mooSig->addSettingGetUsersFromGsuite(True);
$mooSig->addSettingFilterEmailsToUpdate([“$admin_email”]);
$mooSig->updateSignatures();
Hi Danny,
Sorry about my late reply.
Please try testing the below snippet and make sure you update the parts with “REPLACE” with your own settings.
addSettingServiceAccountPath(“/your/project/path/local_vars/”); // REPLACE WITH PATH TO SERVICE ACCOUNT DIR
$mooSig->addsettingSignaturePath(“/your/project/path/signatures/”); // REPLACE WITH PATH TO SIGNATURES DIR
$mooSig->addSettingSetTemplate(“defaultSig.html”);
$mooSig->addSettingRunTestMode(True);
$mooSig->addSettingPreviewSignature(True);
$mooSig->addSettingGetUsersFromGsuite(True);
$mooSig->addSettingFilterEmailsToUpdate([“$admin_email”]);
$mooSig->updateSignatures();
Hello Danny and Moo Master,
I am having the same problem, even by using the snippet above.
What can I do to solve this?
Having the same issue here
@ Danny, how did you resolve this issue “Client is unauthorized to retrieve access tokens using this method”. Even i have the same errors that you had mentioned above.
Hopefully this helps somebody as I struggled with this for longer than I care to admit…. But I added the scope: https://www.googleapis.com/auth/gmail Along with the other 2 listed: https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/gmail.settings.sharing and it finally worked.
Hello,
I’m trying to use your github instructions, but when I load index.php, I got the following erros:
Warning: include(C:\xampp\htdocs\GSuiteSignatureManager-master\vendor\composer/../../src/Gsuite.php): failed to open stream: No such file or directory in C:\xampp\htdocs\GSuiteSignatureManager-master\vendor\composer\ClassLoader.php on line 444
Warning: include(): Failed opening ‘C:\xampp\htdocs\GSuiteSignatureManager-master\vendor\composer/../../src/Gsuite.php’ for inclusion (include_path=’C:\xampp\php\PEAR’) in C:\xampp\htdocs\GSuiteSignatureManager-master\vendor\composer\ClassLoader.php on line 444
Fatal error: Uncaught Error: Class ‘Moometric\mooSignature’ not found in C:\xampp\htdocs\GSuiteSignatureManager-master\index.php:11 Stack trace: #0 {main} thrown in C:\xampp\htdocs\GSuiteSignatureManager-master\index.php on line 11
Please, could you help me this?
@mateus, even i have same errors. Did you find the solution ?
Hi, Thank you for this code. How can i modify to update multiple signatures? Lets say you want to standardize signatures for a whole organization, by running the script once.
Hi Tibi,
Sorry for my super late reply – Yes this is possible (and what i’m using it for right now).
An example here if you want to update all GSuite users without a filter.
Hope this helps!
Best,
MooMaster
Hola, me puedes ayudar con estos Errores:
Warning: include(C:\xampp\htdocs\moometric\GSuite\vendor\composer/../../src/Gsuite.php): failed to open stream: No such file or directory in C:\xampp\htdocs\moometric\GSuite\vendor\composer\ClassLoader.php on line 444
Warning: include(): Failed opening ‘C:\xampp\htdocs\moometric\GSuite\vendor\composer/../../src/Gsuite.php’ for inclusion (include_path=’C:\xampp\php\PEAR’) in C:\xampp\htdocs\moometric\GSuite\vendor\composer\ClassLoader.php on line 444
Fatal error: Class ‘Moometric\mooSignature’ not found in C:\xampp\htdocs\moometric\GSuite\index.php on line 11
I got that error 444 as well and found that if I renamed the file in the project/src/ folder from MooSignature.php to Gsuite.php it ran ok. Looks like there was an update a few months ago.
Hi JH,
I’ve made an update to the repo – the reference should now be fixed. If you clone the repo now there should be no further problems.
Best,
MooMaster
Hi – is there an update on how to overcome these errors:
$ php index.php
Fatal error: Uncaught Google_Service_Exception: {
“error”: “unauthorized_client”,
“error_description”: “Client is unauthorized to retrieve access tokens using this method.”
} in /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Http/REST.php:118
Stack trace:
#0 /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Http/REST.php(94): Google_Http_REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#1 /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Task/Runner.php(176): Google_Http_REST::doExecute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#2 /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Http/REST.php(58): Google_Task_Runner->run()
#3 /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Client.php(798): Google_Http_REST::execute(Ob in /Users/xxx/support/tmp/GSuiteSignatureManager/vendor/google/apiclient/src/Google/Http/REST.php on line 118
My php:
addSettingServiceAccountPath(“/Users/xxx/support/tmp/GSuiteSignatureManager/local_vars/”); // REPLACE WITH PATH TO SERVICE ACCOUNT DIR
$mooSig->addsettingSignaturePath(“/Users/xxx/support/tmp/GSuiteSignatureManager/signatures/”); // REPLACE WITH PATH TO SIGNATURES DIR
$mooSig->addSettingSetTemplate(“defaultSig.html”);
$mooSig->addSettingRunTestMode(True);
$mooSig->addSettingPreviewSignature(True);
$mooSig->addSettingGetUsersFromGsuite(True);
$mooSig->addSettingFilterEmailsToUpdate([“$admin_email”]);
$mooSig->updateSignatures();
?>
Hi Ilium007,
Seems like an issue with your setup. Make sure you have set the correct scopes in GSuite and also Enabled domain wide delegation. ““error”: “unauthorized_client”,
“error_description”: “Client is unauthorized to retrieve access tokens using this method.””
HI – I have gone through all the steps over ten times, removing everything and starting again. I have followed every step to the tee and still get the error. We are using GSuite Basic – is this a problem ?
I went to the instructions on your Git Hub page and saw the additional scope requirements that were not listed on this page:
https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.user.alias,https://www.googleapis.com/auth/admin.directory.userschema,https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/gmail.settings.sharing
It now seems to be working.
Hi, thank you so much for this, it does exactly what it says on the tin and was easy to put together using your instructions.
However I do have one question, how are you maintaining email signatures on gmail apps?
The signature that I have put together doesn’t display on android or IOS.
Hi Scott,
I had the same question in the past – iOS picks up the signature, Android doesn’t. This is a limitation of the Gmail app on android devices (which kind of sucks!). Some more info here. https://www.xink.io/email-signature-ipad-iphone/g-suite-email-signatures/
Thank you for you quick response to my above question.
How does https://www.exclaimer.co.uk/ manage to send signatures via the android application?
I’m guessing it does it through an extension but worth asking.
Thank you so much for this helpful instruction.
After several trial and error, finally it worked.
But with some condition:
– if user already set their signature, the signature will not be updated.
– so, user have to go to Settings > Signature > Select “No Signature” (in this condition, they can receive update from the application)
– user need to re-enable their signature.
Is there something I missed from the step above or someting else?
Thanks for your help.
Hi Hanu,
It should update/overwrite if there is already a signature set. Are you using the github repo I created to update signatures?
Unless google updated something, then this was the standard behavior. I will also do some testing to double check this is still the case.
Regards,
MooMaster
In signature how name, phone number and email address will change automatic once we create new users in Gsuite
Hi Chandan,
It won’t change automatically when you add a new user – The script will need to be run each time a user is created or updated. Right now i’m doing this through a daily cron job which updates all our GSuite users. This ensure that any modifications done by users to their signatures is overwritten with a standard, and new users get the new signature set.
Hope this help.
Best,
MooMaster
It’s possible to insert a check in the template like “if a field in the user account is empty, do not print it out”?
Hi
thanks a lot for this step-by-step tutorial. Works like a charm.
i want to change signature in multiple email , but with this code i can’t do that, is it possible?
Hi
It works on aliases address but not on primary ones. any help?
CODE:
addSettingRunTestMode(False);
$mooSig->addSettingPreviewSignature(True);
// Setting the default signature
$mooSig->addSettingSetTemplate(“mydomain-signature.html”);
echo “From array of users”;
$mooSig->addSettingUnsetFilters();
$mooSig->addSettingUserArray([
[
“primaryEmail” => “[email protected]”,
“alias” => “[email protected]”,
“thumbnailPhotoUrl” => “https://image.svg”,
“fullName” => “My name”,
“phone0” => “My phone”,
“title” => “My title”
],
]);
$mooSig->updateSignatures();
Solved.
I added and additional block for primary emails where the alias is actually the primary email address.
Not really sure should be that way but it works.
Hello,
I don’t know if anyone is still monitoring this guide, but has anyone seen the following error when running index.php:
PHP Fatal error: Uncaught Google_Service_Exception: {
“error”: {
“errors”: [
{
“domain”: “global”,
“reason”: “failedPrecondition”,
“message”: “Mail service not enabled”
}
],
“code”: 400,
“message”: “Mail service not enabled”
}
}
in C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Http\REST.php:118
Stack trace:
#0 C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Http\REST.php(94): Google_Http_REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#1 C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Task\Runner.php(176): Google_Http_REST::doExecute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’)
#2 C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Http\REST.php(58): Google_Task_Runner->run()
#3 C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Client.php(798): Google_H in C:\Users\xxx\vendor\moometric\gsuite\vendor\google\apiclient\src\Google\Http\REST.php on line 118
Prior to the above, it prints the html code in command prompt, so it looks like i’m nearly there.
I’m still in test mode so it’s updating a single user, which is the admin account email address. Gmail is enabled for the admin account and it can send and receive email.
I’ve tried using the email addresses from other user accounts that are set up as G-Suite super admins and they behave slightly different to above. It doesn’t print the HTML, just goes straight to the above error after stating ‘Updating single user from domain.
We’ve got a full license for G-Suite, so a trial license hasn’t expired or anything like that. The 5x API scopes have been added.
This is my first attempt with the G-Suite API. Does the service account need it’s own Gmail account?
Thanks,
Tom