1

My goal is to update all user email signature from my domain.

I have set up a service account with domain-wide delegation authority. But I'm stuck with this error:

{
 "error": {
  "errors": [
   {\n
    "domain": "global",
    "reason": "failedPrecondition",
    "message": "Bad Request"
   }
  ],
  "code": 400,
  "message": "Bad Request"
 }
}

I'm using the same request than the one executed by the API explorer. So it should be well formated...

In the API explorer, it isn't properly working either, i'm having this answer :

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "forbidden",
    "message": "Delegation denied for vivien@mydomain.com"
   }
  ],
  "code": 403,
  "message": "Delegation denied for vivien@mydomain.com"
 }
}

It seems like I have permission problems but I can't figure out why.

Here is my PHP test code for information :

 public function updateSignAction(){

    putenv('GOOGLE_APPLICATION_CREDENTIALS='.$this->get('kernel')->getRootDir().'/../app/Resources/files/mydomain.json');

    $client = new \Google_Client();
    $client->useApplicationDefaultCredentials();
    $client->setApplicationName("demo");
    $client->addScope([
        "https://www.googleapis.com/auth/gmail.settings.basic",
        "https://www.googleapis.com/auth/gmail.settings.sharing"
    ]);
    //$client->setSubject('vivien@mydomain.com');
    $httpClient = $client->authorize();

    $response = $httpClient->put(
       'https://www.googleapis.com/gmail/v1/users/vivien@mydomain.com/settings/sendAs/test',
       [
            'json' => [
                'signature' => "test-via-api"
            ]
        ]
    );

    return $this->render('AdminBundle:GoogleApi:user/update.html.twig', array(
        'response' => $response->getBody()->getContents(),
    ));
}
Vivien
  • 1,159
  • 2
  • 14
  • 34

1 Answers1

0

You must authenticate to the API. To do this, there are two ways:

  • Use OAuth - the Server redirects the user to google's servers, where they can login, grant permission to your app, and pass a token back to you
  • Service Accounts. These are a little bit more complicated:
  • First, you'll have to setup an app (done)
  • Second, you'll have to setup a service account. This is how your app authenticates to google. you've done that, and the certificate you've got contains the private key to authenticate
  • Third, the user needs to grant your application access to act on behalf of them. This is the point you haven't done yet.

So what you're currently trying is to send mails from the service account, but this is not an Gmail Account.

Please also note: With regular GMail Accounts, you can not use 'Service Accounts'. You'll have to use OAuth. To use Service Accounts, you need to be a Google Apps customer.

To grant your Service Account Permissions to send mails on behalf of your GMails/Google Apps accounts, please follow this document. For One or More API Scopes, you'll have to enter https://mail.google.com/,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.compose,https://www.googleapis.com/auth/gmail.send.

After you've setup this, it's possible to send mails, just modify the code as follows:

$results = $service->users_messages->send("me", $msg);

won't work, because 'me' referrs to the service account, which can't send mail (see above). Replace me with the user id (mail-address) of the account from which the mails should be send.:

$results = $service->users_messages->send("senders_mail@domain.com", $msg);

Then, you'll need to add

$cred->sub = 'senders_mail@domain.com';
below

$cred = new \Google_Auth_AssertionCredentials(
  $service_account_name,
  array('https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/gmail.compose'),
  $key
);

<?php
require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php');
$client_id = '*censored*.apps.googleusercontent.com';
$service_account_name = '*censored*@developer.gserviceaccount.com';
$key_file_location = '/tmp/apiKey.p12';

$userid_from='*censored*';
$client = new \Google_Client();
$client->setApplicationName("Client_Library_Examples");

if (isset($_SESSION['service_token'])) {
  $client->setAccessToken($_SESSION['service_token']);
}

$key = file_get_contents($key_file_location);
$cred = new \Google_Auth_AssertionCredentials(
  $service_account_name,
  array('https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/gmail.compose', 'https://www.googleapis.com/auth/gmail.modify','https://www.googleapis.com/auth/gmail.readonly'),
  $key
);
$cred->sub=$userid_from;
$client->setAssertionCredentials($cred);

if ($client->getAuth()->isAccessTokenExpired()) {
  $client->getAuth()->refreshTokenWithAssertion($cred);
}

 $mime = "*censored*";

$service = new \Google_Service_Gmail($client);

$msg = new \Google_Service_Gmail_Message();
$msg->setRaw($mime);

try {
  $results = $service->users_messages->send($userid_from, $msg);
  print 'Message with ID: ' . $results->id . ' sent.';
} catch (\Exception $e) {
  print 'An error occurred: ' . $e->getMessage();
}

If there are any questions left, feel free to ask!

Android Enthusiast
  • 4,826
  • 2
  • 15
  • 30
  • I followed your exemple but with some code update [upgrading.md](https://github.com/google/google-api-php-client/blob/master/UPGRADING.md#google_auth_assertioncredentials-has-been-removed). I still have an error : `{ "error": "unauthorized_client", "error_description": "Unauthorized client or scope in request." }` – Vivien Dec 07 '16 at 11:28
  • And i have nothing under "Advanced settings > Authentication" in the admin panel, could be the problem ? – Vivien Dec 07 '16 at 11:46