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(),
));
}
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!
Related
I'm updating a PHP application to create new "send mail as" accounts in Gmail (using the Google Service Gmail). I'm able to connect to the account and view alias information from my code so the connection is not the issue. Here is my code
$scopes = array(
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/admin.directory.domain',
'https://www.googleapis.com/auth/siteverification',
'https://www.googleapis.com/auth/gmail.settings.sharing',
'https://www.googleapis.com/auth/gmail.settings.basic'
);
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->setSubject('mymainemail#email.com');
$client->setScopes($scopes);
try {
$gmail = new Google_Service_Gmail($client);
$smtpadd = new Google_Service_Gmail_SendAs(array('displayName' => 'display name','sendAsEmail' => 'myalias#email.com','treatAsAlias' => false, 'isPrimary' => 'true', 'isDefault' => 'false', 'smtpMsa' => array(
'host' => 'smtp.host',
'port' => 587,
'username' => 'username',
'password' => 'mypassword'
)));
$results = $gmail->users_settings_sendAs->create('mymainemail#email.com',$smtpadd);
} catch (exception $e) {
print "Error" . $e->getMessage();
}
The only time I get a 500 internal error is when I try to add a new "send mail as" account with smtp MSA information. Also this code was working before and recently stop and gave me the 500 internal error.
Here is the error code
Google\Service\Exception: {
"error":
{
"code": 500,
"message": "Internal error encountered.",
"errors": [
{
"message": "Internal error encountered.",
"domain": "global", "reason": "backendError"
} ],
"status": "INTERNAL"
}
}
In order to send emails with a service account your workspace admin must have configured domain wide delegation to the user on your service account who you wish you send emails on behalf of.
This code should show you how to authorize your application. It will just list all the messages from your delegated user.
scopes = array(
'Google_Service_Gmail::GMAIL'
);
$client = new Google_Client();
$client->setApplicationName("Gmail delegation sample");
$client->setAuthConfig($GOOGLE_AUTH);
$client->setScopes($scopes);
$client->setSubject("user#YourDomain.com");
$service = new Google_Service_Gmail($client);
$messages = $service->users_messages->listUsersMessages('me');
print_r($messages);
If that works then you should consult users.settings.sendAs#SendAs to check the property body for the users_settings_sendAs->create method.
$alias = new Google_Service_Gmail_SendAs();
$alias ->sendAsEmail('Alias#yourdomain.com');
$service->users_settings_sendAs->create($this->email, $this->email, $alias);
I want to change all signatures from my Gmail domain. This domain has many accounts, and I need to change it from server-side.
I'm using php, and I started my project with:
php composer.phar require google/apiclient:2.0
I wrote one code, but when I try to update one email (like teste#mydomain.com), I receive:
{ "error": { "errors": [ { "domain": "global", "reason": "insufficientPermissions", "message": "Insufficient Permission" } ], "code": 403, "message": "Insufficient Permission" } }
My code (using API client library) is something like:
<?php
// initialize gmail
function getService() {
try {
include_once __DIR__ . '/vendor/autoload.php';
$client = new Google_Client();
$credentials_file = __DIR__ . '/credentials/gmailAPI.json';
// set the location manually. Credential server-side
$client->setAuthConfig($credentials_file);
$client->setApplicationName("GmailAPI");
$client->setScopes(['https://apps-apis.google.com/a/feeds/emailsettings/2.0/']);
$gmail = new Google_Service_Gmail($client);
return $gmail;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
function updateSignature(&$gmail) {
try {
// Start sendAs
$signature = new Google_Service_Gmail_SendAs();
// Configure Signature
$signature->setSignature("Any HTML text here.");
// Update account and print answer
var_dump($gmail->users_settings_sendAs->update("someEmail#myDomain.com.br","someEmail#myDomain.com.br",$signature));
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
try {
$gmail = getService();
updateSignature($gmail);
} catch (Exception $e) {
echo $e->getMessage();
}
?>
My credential file (gmailAPI.json) is one service account key, and I'm using Google for Work.
I created this credential using one administrator account from this domain.
My credential file is:
{
"type": "service_account",
"project_id": "myProjectId",
"private_key_id": "myPrivateKeyid",
"private_key": "myPrivateKey",
"client_email": "gmailapi#projectid.iam.gserviceaccount.com",
"client_id": "myId",
"auth_uri": "url",
"token_uri": "url",
"auth_provider_x509_cert_url": "url",
"client_x509_cert_url": "url"
}
Edit 1
I changed the scopes as instructed, and now my scopes are:
$client->setScopes(['https://www.googleapis.com/auth/gmail.settings.basic','https://www.googleapis.com/auth/gmail.settings.sharing']);
I also added permision on Google (/AdminHome?chromeless=1#OGX:ManageOauthClients) to my service account key.
I tried API explorer and it works. When i changed the scopes, the error changed to:
{ "error": { "errors": [ { "domain": "global", "reason": "failedPrecondition", "message": "Bad Request" } ], "code": 400, "message": "Bad Request" } }
I'm using this command:
var_dump($gmail->users_settings_sendAs->update("someEmail#myDomain.com.br","someEmail#myDomain.com.br",$signature));
I tried also
var_dump($gmail->users_settings_sendAs->get("someEmail#myDomain.com.br","someEmail#myDomain.com.br"));
But I received same error.
Thank You everyone.
I tried a lot of codes, and finally found one that works.
include_once __DIR__ . '/vendor/autoload.php';
// credential file (service account)
$credentials_file = __DIR__ . '/credentials/gmailAPI.json';
putenv('GOOGLE_APPLICATION_CREDENTIALS='.$credentials_file);
// Initialize Google Client
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
// scopes to change signature
$client->setScopes(['https://www.googleapis.com/auth/gmail.settings.basic','https://www.googleapis.com/auth/gmail.settings.sharing']);
// *important* -> Probably because delegated domain-wide access.
$client->setSubject("admEmailHere#test.com");
// Initialize Gmail
$gmail = new Google_Service_Gmail($client);
// set signature
$signature = new Google_Service_Gmail_SendAs();
$signature->setSignature("HTML code here.");
// update signature
$response = $gmail->users_settings_sendAs->update("admEmailHere#test.com","admEmailHere#test.com",$signature)->setSignature();
// get signature
$response = $gmail->users_settings_sendAs->get("admEmailHere#test.com","admEmailHere#test.com")->getSignature();
echo json_encode($response);
I commented all code, and I used https://developers.google.com/api-client-library/php/auth/service-accounts to create it.
Atention -> You need to give permission on Gmail, and create server key (with domain-wide access).
I think your access token doesn't contain all scopes you want. First try in API explorer. Check what are the scopes API explorer request from you and then add those scopes to your code(place where you get permission).
https://developers.google.com/apis-explorer
hope this solves your problem
Well, the error 403 or Insufficient Permission is returned when you have not requested the proper or complete scopes you need to access the API that you are trying to use. Here is the list of scopes with description that you can use with Gmail API.
To know the scope that you are using, you can verify it with this:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=xxxxxx
Note: You need to include all the scope that you are using and make
sure you enable all the API that you use in the Developer Console.
This Delegating domain-wide authority to the service
account
might also help.
For more information, check these related SO questions:
Gmail API: Insufficient Permission
How do I get around HttpError 403 Insufficient Permission?
I'm trying to set publish permissions for gmail to a pubsub topic in google cloud.
The application where I implemented this code is running in AWS.
It's a PHP application and I'm using version 2.0.0-RC7 of the google PHP api client.
In code, I implemented the flow as described in the documentation:
Create a topic (Works)
Create a subscription (works)
Grant publish rights to gmail (here I get stuck)
The first two actions are done with the same google client instance, that is authenticated with the service account credentials.
The code:
$scopes = [
'https://www.googleapis.com/auth/pubsub',
'https://mail.google.com',
];
$pushEndpoint = 'https://some.url/google_notifications/';
$client = new Google_Client();
$client->setScopes($scopes);
$client->setAuthConfig($serviceAccountInfo);
if ($client->isAccessTokenExpired()) {
$client->refreshTokenWithAssertion();
}
$service = new Google_Service_Pubsub($client);
// This part works
$topicObject = new Google_Service_Pubsub_Topic();
$topicObject->setName($this->getTopicName());
$service->projects_topics->create($this->getTopicName(), $topic);
// This part also works
$push = new Google_Service_Pubsub_PushConfig();
$push->setPushEndpoint($pushEndpoint);
$subscription = new Google_Service_Pubsub_Subscription();
$subscription->setName($this->getSubscriptionName());
$subscription->setTopic($this->getTopicName());
$subscription->setPushConfig($push);
$service->projects_subscriptions->create($this->getSubscriptionName(), $subscription);
// This part gives the error
$binding = new Google_Service_Pubsub_Binding();
$binding->setRole('roles/pubsub.publisher');
$binding->setMembers(['serviceAccount:gmail-api-push#system.gserviceaccount.com']);
$policy = new Google_Service_Pubsub_Policy();
$policy->setBindings([$binding]);
$setRequest = new Google_Service_Pubsub_SetIamPolicyRequest();
$setRequest->setPolicy($policy);
try {
$result = $service->projects_topics->setIamPolicy($this->getTopicName(), $setRequest);
var_dump($result);
} catch (\Exception $e) {
echo $e->getMessage();
}
The result is always:
{
"error": {
"code": 403,
"message": "User not authorized to perform this action.",
"errors": [
{
"message": "User not authorized to perform this action.",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
}
}
Can someone tell me what I'm doing wrong ?
It's really annoying to set those permissions by hand all the time.
Thanks.
To use projects.topics.setIamPolicy method your service account must have a "Pub/Sub Admin" role. You can change a role of the account by visiting "IAM & admin" page for your project: https://console.cloud.google.com/iam-admin/iam
Okay... I have to say I don't have enough experience on using Google's API, so I'll try to explain as detail as I could.
I need to use PHP to grab the Cloud storage's data, so I tried my credential with gsUtil to grab data from bucket and it works; But when I try to use PHP library to grab data, the API replied me with this content:
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Forbidden"
}
],
"code": 403,
"message": "Forbidden"
}
Since it didn't tell me exactly which step is wrong, so I searched around this site and tried everything which looked similar, but the Situation stands.
Here is the Configuration on my Google Dev. Console:
Api Manager > Overall > Enabled APIļ¼
(a)Drive API.
(b)Cloud Storage.
(c)Cloud Storage JSON API.
Api Manager > Credentials:
(a)Api Key / OAuth 2.0 ID / Service Acc. Key are created.
(b)Server IPs are added to the Api key's accept IP list.
(c)Service Account have the Editor permission to the Project, service acc key is bind to this account too.
In PHP:
$email = '<my gmail>';
$scope = 'https://www.googleapis.com/auth/cloud-platform';
$apiKey = '<my api key>';
$oAuthId = '<OAuth ID>';
$serviceAcc = '<service account id>#developer.gserviceaccount.com';
$keyFileLocation = $_SERVER['DOCUMENT_ROOT']. "/<p12 file>";
$bucketId = '<my bucket id>';
$list = array();
$client = new Google_Client();
$client->setApplicationName("gp-api");
$client->setDeveloperKey($apiKey);
$cred = new Google_Auth_AssertionCredentials (
$serviceAcc,
array($scope),
file_get_contents($keyFileLocation)
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired())
$client->getAuth()->refreshTokenWithAssertion($cred);
if($client->getAccessToken()) {
$reqUrl = "https://www.googleapis.com/storage/v1/b/$bucketId/o/";
$request = new Google_Http_Request($reqUrl, 'GET', null, null);
$httpRequest = $client->getAuth()->authenticatedRequest($request);
if ($httpRequest->getResponseHttpCode() == 200) {
$objects = json_decode($httpRequest->getResponseBody());
foreach ($objects->items as $object) {
$list[] = $object->mediaLink;
}
}
else {
echo $httpRequest->getResponseHttpCode(); // This is where I got the 403
}
}
Please tell me if I missed something.
Ok, I got the Problem: it must impersonate the User account which have the privilege to access the API scope that I mentioned in program.
So some additional codes must be added as following:
$email = '<email account which could access that api>';
$scope = 'https://www.googleapis.com/auth/cloud-platform';
$apiKey = '<my api key>';
$oAuthId = '<OAuth ID>';
$serviceAcc = '<service account id>#developer.gserviceaccount.com';
$keyFileLocation = $_SERVER['DOCUMENT_ROOT']. "/<p12 file>";
$bucketId = '<my bucket id>';
$list = array();
$client = new Google_Client();
$client->setApplicationName("gp-api");
$client->setDeveloperKey($apiKey);
$cred = new Google_Auth_AssertionCredentials (
$serviceAcc,
array($scope),
file_get_contents($keyFileLocation),
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer',
$email
);
Woooooyaaaaa, another problem solved! time to move up for next problem.
When I try to fetch data from Google Analytics, I got error
Error refreshing the OAuth2 token, message: '{ "error" :
"unauthorized_client", "error_description" : "Unauthorized client or
scope in request." }'
I create project in my https://console.developers.google.com/project, create Service account and download .p12 key. Also enable "Analytics API" in project settings, but it doesn't work. This is my code:
$service_account_name = '<Service Email>#developer.gserviceaccount.com';
$key_file_location = '<keyName>.p12';
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array(Google_Service_Analytics::ANALYTICS),
$key,
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer',
'<My email>'
);
$client->getAuth()->setAssertionCredentials($cred);
$service = new Google_Service_Analytics($client);
$result = $service->data_ga->get("ga:<profileID>", "yesterday", "today", "ga:pageviews");
print_r( $result);
What is wrong with my project? Please help.
You are missing the final step which is giving access to your application in the control panel of your domain.
https://developers.google.com/+/domains/authentication/delegation
You created the service account, now you need to delegate/authorize the application.