read & send email with gmail api using service account - php

I need a cron to run in my shared host which will scan my gmail account every 30 minutes and will reply all unread email using PHP
First I downloaded the apiclient with composer -> { "require": { "google/apiclient": "1.*" } } . Then I create the service account(https://console.developers.google.com/apis/credentials/serviceaccountkey?project=xxxxxx) and get a json file which has these values :
"type": "service_account",
"project_id": "xxxxxx",
"private_key_id": "xyxyxyxyyxyxy",
"private_key": "-----BEGIN PRIVATE KEY-----\ndddddddddddddddmr\n-----END PRIVATE KEY-----\n",
"client_email": "yy-yyy#zzzz-zzzzzz.iam.gserviceaccount.com",
"client_id": "11763887676776474",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxx%40zzz-zzzzzz.iam.gserviceaccount.com"
Also made sure gmail api is enabled(from).
Now I wondering How I connect with gmail and just read the un-read email using php...
I was modifying a example code but stuck here($apiKey =)...
<?php
include_once "vendor/google/templates/base.php";
echo pageHeader("Simple API Access");
require_once realpath(dirname(__FILE__) . '/vendor/google/apiclient/src/Google/autoload.php');
$client = new Google_Client();
$client->setApplicationName("Gmail access test");
$apiKey = "<YOUR_API_KEY>"; // WHICH VALUE i SHOULD PUT HERE????.
// Warn if the API key isn't changed.
if (strpos($apiKey, "<") !== false) {
echo missingApiKeyWarning();
exit;
}
$client->setDeveloperKey($apiKey);
$service = new Google_Service_Books($client);
...
...
...
UPDATE : my updated code looks like this
<?php
require_once realpath(dirname(__FILE__) . '/vendor/google/apiclient/src/Google/autoload.php');
session_start();
$scopes = array(
Google_Service_Gmail::GMAIL_READONLY,
Google_Service_Gmail::GMAIL_COMPOSE,
Google_Service_Gmail::GMAIL_SEND,
Google_Service_Gmail::MAIL_GOOGLE_COM,
);
$client = new Google_Client();
$arDetails = $client->loadServiceAccountJson('99b15f1f2326.json', $scopes);
$client->setAssertionCredentials($arDetails);
$client->setScopes($scopes);
$fl = $client->getAuth()->isAccessTokenExpired() ;
if($fl) {
$client->getAuth()->refreshTokenWithAssertion($arDetails);
}
$client->setAccessType('offline');
$gmailService = new Google_Service_Gmail($client);
#$users = $gmailService->users;
$users = $gmailService->users_messages;
$optParams['maxResults'] = 5; // Return Only 5 Messages
$optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
$messages = $gmailService->users_messages->listUsersMessages('me',$optParams);
echo '<br/><pre>';
print_r($users);
print_r($messages);
----
---
---
But I am getting error -
PHP Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling GET https://www.googleapis.com/gmail/v1/users/me/messages?maxResults=5&labelIds=INBOX: (400) Bad Request' in /home3/shafico1/public_html/imsdev/frontend/web/atiq/vendor/google/apiclient/src/Google/Http/REST.php:110
Stack tra

Related

Google Cloud - Save Email Attachments (invoices) then Delete

I've coded the script below. This code connects to a Gmail account, searches for emails with attachments, and saves the attachments to Google Drive. It also deletes the emails from the Gmail account.
But anytime I run it:
Fatal error: Uncaught Google\Service\Exception: { "error": { "errors": [ { "domain": "global", "reason": "required", "message": "Login Required", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Login Required" } }
I tried several changes. Nothing works. Even ChatGPT cannot find the fix/error.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Include the autoload file
require_once __DIR__ . '/vendor/autoload.php';
// Set your OAuth 2.0 Client IDs
$client_id = '123456789012-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com';
$client_secret = 'ABC-XYZ_123';
// Set your redirect URI
$redirect_uri = 'https://example.com/invoices';
// Create a new Google_Client object
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
// Set the scopes for the API services you want to use
$client->addScope(Google_Service_Drive::DRIVE);
// Authorize the client
$client->authorize();
// Create a new Google_Service_Drive object
$driveService = new Google_Service_Drive($client);
// Connect to Gmail
$hostname = '{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX';
$username = 'email#gmail.com';
$password = 'password';
// Connect to Gmail
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to Gmail: ' . imap_last_error());
// Get all emails from inbox
$emails = imap_search($inbox,'ALL');
// If emails are returned
if($emails) {
// Sort emails by date
rsort($emails);
// Loop through emails
foreach($emails as $email_number) {
// Get the full header of the email
$header = imap_fetchheader($inbox, $email_number);
// Parse the header into an object
$header_obj = imap_rfc822_parse_headers($header);
// Get the original sender's name
$sender_name = $header_obj->from[0]->personal;
// Get the date the email was sent
$date_sent = strtotime($header_obj->date);
$formatted_date_sent = date("Y-m-d", $date_sent);
// Get the attachments
$attachments = imap_fetchstructure($inbox,$email_number);
// If attachments are found
if(isset($attachments->parts) && count($attachments->parts)) {
// Loop through attachments
for($i = 0; $i < count($attachments->parts); $i++) {
// Check if the attachment is an object
if (is_object($attachments->parts[$i])) {
// Get the attachment data
$attachment_data = imap_fetchbody($inbox,$email_number,$i+1);
// Decode the attachment data
$attachment_data = base64_decode($attachment_data);
// Create the filename
$filename = $formatted_date_sent . ' ' . $sender_name;
// Save the attachment to Google Drive
$file = new Google_Service_Drive_DriveFile();
$file->setName($filename);
$file->setDescription('Invoice attachment');
$file->setMimeType('application/pdf');
$file->setParents(array('1nkfPyEvFYR_DGUGJDiy8WLx_ANUNsAdW'));
$createdFile = $driveService->files->create($file, array(
'data' => $attachment_data,
'mimeType' => 'application/pdf',
'uploadType' => 'multipart'
));
}
}
}
// Delete the email
imap_delete($inbox,$email_number);
}
}
// Close the connection
imap_close($inbox);
?>
From what I can see you are simply creating a drive service object but not acutally calling any authorization on it.
// Create a new Google_Service_Drive object
$driveService = new Google_Service_Drive($client);
You need to request consent of the user who's drive account you want to write to. With out that your service object is not authorized and you will get a "Login Required" error messages becouse your not logged in.
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
Code ripped from Oauth2Authentication.php

php server google drive download file in background

I need form PHP level, in background without user interaction login on google drive and get files list. I found similar topic and code for question working, but is required handly login, where I need login from php in background.
In second post with code for possibly login witout user interaction, but I don't know where is bug.
My code PHP:
<?php
require_once 'vendor/autoload.php';
require_once 'src/Google_Client.php';
require_once 'src/contrib/Google_DriveService.php';
require_once 'src/auth/Google_AssertionCredentials.php';
$client_email = 'xxxxxx#xxxxxxxxxxxxx.xxx.gserviceaccount.com';
$private_key = file_get_contents('key.p12');
$user_to_impersonate = 'xxxxxxxxxxxxxxx#gmail.com';
$scopes = array('https://www.googleapis.com/auth/drive');
$credentials = new Google_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service = new Google_Service_Drive($client);
$files = $service->files->listFiles();
echo "count files=".count($files)."<br>";
foreach( $files as $item ) {
echo "title=".$item['title']."<br>";
}
?>
Vendor directory I get from this instruction, and other files I get from this GitHub
I had problem with function Google_Auth_AssertionCredentials, PHP hasn't file with this function. I found that file src/auth/Google_AssertionCredentials.php has similar function Google_AssertionCredentials. I included Google_AssertionCredentials.php file and changed function name.
In finally I have new error:
PHP Fatal error: Cannot call constructor in
\google_drive\vendor\google\apiclient-services\src\Google\Service\Drive.php
on line 75
I don't know what doing again. I tried many other metod for login on google drive, eg. load file list GET method with API_KEY, or via json file.
As result I want get file list, download them. edit and upload.
Any sugestions?
EDIT:
I have part sucess. I found liblary this, and them work with this code:
<?php
function retrieveAllFiles($service) {
$result = array();
$pageToken = NULL;
do {
try {
$parameters = array();
if ($pageToken) {
$parameters['pageToken'] = $pageToken;
}
$files = $service->files->listFiles($parameters);
$result = array_merge($result, $files->getItems());
$pageToken = $files->getNextPageToken();
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
$pageToken = NULL;
}
} while ($pageToken);
return $result;
}
session_start();
require_once '/google-api-php-client/autoload.php';
$client_email = 'xxxx#xxxxx.iam.gserviceaccount.com';
$user_to_impersonate = 'xxxxxx#gmail.com';
$private_key = file_get_contents('key.p12');
$scopes = array('https://www.googleapis.com/auth/drive');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer',
$user_to_impersonate
);
$client = new Google_Client();
if(isset($_SESSION['service_token'])==false && $_SESSION['service_token']=='') {
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($credentials);
}
$_SESSION['service_token'] = $client->getAccessToken();
}
if(isset($_SESSION['service_token']) && $_SESSION['service_token']) {
$client->setAccessToken($_SESSION['service_token']);
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
$_SESSION['service_token'] = $client->getAccessToken();
}
$service = new Google_Service_Drive($client);
print_r(retrieveAllFiles($service));
}
?>
And in result I have only one file [originalFilename] => Getting started, this is PDF, but I don't see this file on Gogle dirve. On google drive I uploaded file: README.md.
I'm not sure, but maybe this file is on ` 'xxxx#xxxxx.iam.gserviceaccount.com' and script not logged to 'xxxxxx#gmail.com'?

Google API error

I am trying to use google API to get events off calendars on an account. I am using a service account. I am receiving two errors when I attempt to manually echo the code or it will remain a blank page if I use foreach(...).
Here are the two errors:
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling GET https://www.googleapis.com/calendar/v3/users/me/calendarList/primary: (404) Not Found' in C:\wamp\www\newOLP\scripts\oAuth2\Google\Http\REST.php on line 110
( ! ) Google_Service_Exception: Error calling GET https://www.googleapis.com/calendar/v3/users/me/calendarList/primary: (404) Not Found in C:\wamp\www\newOLP\scripts\oAuth2\Google\Http\REST.php on line 110
Here is my code:
require_once 'Google/autoload.php';
session_start();
/************************************************
The following 3 values an befound in the setting
for the application you created on Google
Developers console. Developers console.
The Key file should be placed in a location
that is not accessable from the web. outside of
web root.
In order to access your GA account you must
Add the Email address as a user at the
ACCOUNT Level in the GA admin.
************************************************/
$client_id = $jsonDecode['client_id'];
$Email_address = $jsonDecode['client_email'];
$key_file_location = 'privateKey.p12';
$client = new Google_Client();
$client->setApplicationName("CalCon");
$key = file_get_contents($key_file_location);
// separate additional scopes with a comma
$scopes ="https://www.googleapis.com/auth/calendar.readonly";
$cred = new Google_Auth_AssertionCredentials(
$Email_address,
array($scopes),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service = new Google_Service_Calendar($client);
?>
<html><body>
<?php
$calendarList = $service->calendarList->listCalendarList();
echo $service->calendars->get('primary')->getSummary()."<br />";
echo $service->calendarList->get('primary')->getSummary();
while(true) {
foreach ($calendarList->getItems() as $calendarListEntry) {
echo $calendarListEntry;
echo "hi";
echo $calendarListEntry->getSummary()."<br>\n";
// get events
$events = $service->events->listEvents($calendarListEntry->id);
foreach ($events->getItems() as $event) {
echo "-----".$event->getSummary()."<br>";
}
}
$pageToken = $calendarList->getNextPageToken();
if ($pageToken) {
$optParams = array('pageToken' => $pageToken);
$calendarList = $service->calendarList->listCalendarList($optParams);
} else {
break;
}
}
?>
</body></html>

Bad Request while accesing Gmail API

I'm trying to connect to Gmail but server says:
Uncaught exception 'Google_Service_Exception' with message 'Error calling
GET https://www.googleapis.com/gmail/v1/users/{test}%40gmail.com/messages:
(400) Bad Request' in C:\...\google-api-php-client\src\Google\Http\REST.php on line 110
I can't seem to find the problem. Here's the code:
$google_accounts = $this->getGoogleAccounts();
if (count($google_accounts) > 0) {
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/autoload.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/Client.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/Service/Gmail.php';
$scopes = array(
'https://mail.google.com',
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.modify',
);
$key_file_location = $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/keys/';
foreach ($google_accounts as $one_account) {
if (!empty($one_account->client_id) && !empty($one_account->service_mail) && !empty($one_account->key_file)) {var_dump($one_account);
$key = file_get_contents($key_file_location . $one_account->key_file);
$client = new Google_Client();
$cred = new Google_Auth_AssertionCredentials($one_account->service_mail, $scopes, $key);
$client->setAssertionCredentials($cred);
$client->setClientId($one_account->client_id);
$client->setAccessType('offline_access');
$service = new Google_Service_Gmail($client);
$opt_param = array();
$messagesResponse = $service->users_messages->listUsersMessages($one_account->login, $opt_param);
var_dump($messagesResponse);
}
}
return $list;
}
else {
return false;
}
You need to add:
$cred->sub = $userEmail;
right after creating $cred where $userEmail is the email address of the user you are trying to impersonate. For reference, see the Google Drive Service Account documentation which uses a different scope and API call but is otherwise similar to what you'd want to do with Gmail API.

Bigquery API php authorization

I'm trying to get access bigquery api using PHP library, but I always have this error:
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling GET https://www.googleapis.com/bigquery/v2/projects/primeval-shadow-571/datasets/Test/tables: (401) Login Required' in ...
I have a web application, that needs to get some data from table in bigquery. The Remote account is not mine, but it was created by some guy (and I don't have login and pass to log in), who gave me the .json file which included thoose parameters:
auth_uri,
client_secret,
token_uri,
client_email,
client_x509_cert_url,
client_id and
auth_provider_x509_cert_url.
Here is my php code:
<?php
require_once 'Google/Client.php';
require_once 'Google/Service/Bigquery.php';
$client = new Google_Client();
$client->setAuthConfigFile('google-config.json');
$service = new Google_Service_Bigquery($client);
$service->tables->listTables('primeval-shadow-571', 'Test');
But finally I got error that's above.
Can anybody tell me where am I wrong?
P.S. I just started work with google api two days ago, so I'm just beginning learn it.
Thanks a lot.
Here is a sample code that works for us:
session_start();
define('PROJECT_ID', 'edited');
define('DATASET_ID', 'edited');
define('API_KEY', 'edited');
$client_id = 'edited';
$service_account_name = 'edited';
$key_file_location = '.ssh/privatekey-bigquery.p12';
$service_token_file_location = 'bigquery_current_service_token.json';
set_include_path("google-api-php/src/" . PATH_SEPARATOR . get_include_path());
require_once 'google-api-php/src/Google/Client.php';
require_once 'google-api-php/src/Google/Service/Bigquery.php';
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
//$client->setDeveloperKey(API_KEY);
if (!is_file($service_token_file_location)) {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
file_put_contents($service_token_file_location, '');
} else {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
}
$service_token = #file_get_contents($service_token_file_location);
if (!empty($service_token)) {
$client->setAccessToken($service_token);
}
if (!file_exists($key_file_location)) {
die('Key file is missing: ' . $key_file_location);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name, array(
'https://www.googleapis.com/auth/bigquery',
), $key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = $client->getAccessToken();
file_put_contents($service_token_file_location, $service_token);
// start using $client

Categories