2

I want to edit signatures of users in a google apps domain. I plan to use a service account. The service account is delegated to the entire domain. I have this working with the gmail API to send and retrieve email, but signatures are modified using a different api. According to https://developers.google.com/admin-sdk/email-settings/ this api is the Admin SDK which I have enabled via Google Developer Console.

I am trying to use the library gdata.apps.emailsettings.client (which doesn't have Python 3.x support)

Building the credentials works, but when I try to do

gmail_client.RetrieveSignature(username)

I get gdata.client.Unauthorized: Unauthorized - Server responded with: 401.

# python 2.7 from macports    
def setup_gmail_client_new_api():
        client_email = '...3@developer.gserviceaccount.com'

        key_path = 'VCI-EMAIL-INTEGRATION-f493528321ba.json'
        sender = 'tim@vci.com.au'
        API_scope = 'https://apps-apis.google.com/a/feeds/emailsettings/2.0/'
                                            filename=key_path, scopes=API_scope)
        credentials = ServiceAccountCredentials.from_json_keyfile_name(key_path, scopes=API_scope)
        return credentials


    if __name__ == "__main__":
        credentials = setup_gmail_client_new_api()
        client = gdata.apps.emailsettings.client.EmailSettingsClient(domain='vci.com.au')

        auth = gdata.gauth.OAuth2Token(
            credentials.client_id,#serviceEmail
            credentials.client_secret,#private key
            scope='https://apps-apis.google.com/a/feeds/emailsettings/2.0/',
            access_token=credentials.access_token,
            refresh_token=credentials.refresh_token,
            user_agent=credentials.user_agent)

        auth.authorize(client)
        result = retrieve_sig(client,"tim")
        print (result)

the attempt to retrieve the signature:

gdata.client.Unauthorized: Unauthorized - Server responded with: 401,

the service account has domain-wide delegation. In the google apps domain security control panel (Manage API client access), the service ID has permission for "Email Settings (Read/Write) https://apps-apis.google.com/a/feeds/emailsettings/2.0/"

Tim Richardson
  • 6,608
  • 6
  • 44
  • 71
  • I've come up with this script to update all users signature, it requires both oath and service_account credentials, If i have time i will update the README, until then, I belive this code deserves to take a look https://github.com/ozanerturk/googleworkspace-update-all-users-email-signatures – Ozan ERTÜRK Sep 20 '22 at 09:38

2 Answers2

3

Email settings API requires you to authenticate as a super admin, regular users can't access the API. So your service account should be acting as the super admin and then the super admin making the change for the user specified in the API call.

Jay Lee
  • 13,415
  • 3
  • 28
  • 59
  • the user tim@vci.com.au is a super admin on this domain. Where in the process do I authenticate as a user? I thought ClientLogin was deprecated. is this still correct then?: client.ClientLogin(email='adminUsername@yourdomain', password='adminPassword', source='your-apps') what goes in source='your-apps'? – Tim Richardson Apr 14 '16 at 22:04
  • 1
    I tried a different approach based on your answer here: http://stackoverflow.com/a/29612057/401226 client.RetrieveSiganture('tim') now causes:

    Token invalid - Invalid token: Cannot parse referred token string: Invalid gaia_data.AuthSubToken proto on base64 token: 6��

    Error 401

    – Tim Richardson Apr 15 '16 at 03:42
1

Please note: this answer is out of date and uses a deprecated API. This gist shows the new way of doing it (and in python3) https://gist.github.com/timrichardson/e6ee6640a8b7fe664f3a5a80406ca980


Right. I hope this post saves hours of work.

Key missing point which was not documented very well (ok, not at all, but perhaps I missed it). You need to use delegated_credentials and authorise the email_settings_client with that object.

  1. Follow the oauth2 notes to make a service account and download a JSON private key as usual. You do that on the developer console. The service account is not linked to any domain, it is just a credential.
  2. In your google apps domain, go the security, advanced, api etc etc. Steps 1 & 2 are currently documented here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority

Now, the python code. I used 2.7 because I think gdata is not v3 compatible.

This is a minimal example.

from __future__ import print_function

import httplib2
from oauth2client.service_account import ServiceAccountCredentials
import gdata.apps.emailsettings.client
import gdata.gauth

def setup_credentials():
        key_path = '/Users/tim/Dropbox/pycharm_projects_27/gmail_admin/<blabla>.json'
        API_scopes =['https://apps-apis.google.com/a/feeds/emailsettings/2.0/']
        credentials = ServiceAccountCredentials.from_json_keyfile_name(key_path, scopes=API_scopes)
        return credentials

if __name__ == "__main__":
    credentials = setup_credentials()

    # pass the email address of a domain super-administrator
    delegated_credentials = credentials.create_delegated('tim@vci.com.au')
    http = httplib2.Http()
    #http = credentials.authorize(http)
    http = delegated_credentials.authorize(http)  #this is necessary


    url_get_sig = 'https://apps-apis.google.com/a/feeds/emailsettings/2.0/vci.com.au/tim/signature'
    r = http.request(url_get_sig,"GET")
    print (r)

    # now use the library
    client = gdata.apps.emailsettings.client.EmailSettingsClient(domain='vci.com.au')
    auth2token = gdata.gauth.OAuth2TokenFromCredentials(delegated_credentials)
    auth2token.authorize(client)
    r = client.retrieve_signature('tim')
    print (client)

this is a richer example here: https://gist.github.com/timrichardson/a43462aedc0797ecb76c48deb9c96d36

Tim Richardson
  • 6,608
  • 6
  • 44
  • 71