Anandhan
Anandhan

Reputation: 432

Reading messages from Gmail, in PHP, using Gmail API

I have donwloaded new Gmail API source code from Google PHP client library.

I inititalized the service using:

set_include_path("./google-api-php-client-master/src/".PATH_SEPARATOR.get_include_path());
    
require_once 'Google/Client.php';   
require_once 'Google/Service/Gmail.php';

$client = new Google_Client();
$client->setClientId($this->config->item('gmailapi_clientid'));
$client->setClientSecret($this->config->item('gmailapi_clientsecret'));
$client->setRedirectUri(base_url('auth'));
$client->addScope('email');
//$client->addScope('profile');     
$client->addScope('https://mail.google.com');           
$client->setAccessType('offline');

$gmailService = new Google_Service_Gmail($client);

What should I do next? How to read Gmail messages using Gmail API PHP library?

Upvotes: 24

Views: 49084

Answers (5)

AQuirky
AQuirky

Reputation: 5266

Building on the excellent answers from @Samphors and @Muffy, here is how you would do this in the MVC world of Symfony

My controller...

class GMailController extends AbstractController
{
    /**
     * @Route("/g/mail", name="app_g_mail")
     */
    public function index(Request $request): Response
    {
        $code = $request->query->get('code');
        return $this->render('g_mail/index.html.twig', [
            'controller_name' => 'GMailController',
            'code' => $code
        ]);
    }
    /**
     * @Route("/g/mail/test", name="app_g_mail_test", methods={"POST"})
     */
    public function test(Request $request) : Response
    {
        $filepath = '../client_secret.json';
        $contents = file_get_contents($filepath);
        $client = new Client();
        $client->setApplicationName('Gmail_test');
        $client->setAuthConfigFile($filepath);
        $client->addScope('email');
        $client->addScope('https://mail.google.com');
        $client->setRedirectUri('https://localhost:8005/g/mail');
        $client->setAccessType('offline');
        // Redirect the URL after OAuth
        $code = $request->request->get('code');
        if ($code) {
            error_log('code is set = '.$code);
            $client->authenticate($code);
            $_SESSION['access_token'] = $client->getAccessToken();
        }
        
        // If Access Toket is not set, show the OAuth URL
        if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
            error_log('setting access token');
            $client->setAccessToken($_SESSION['access_token']);
        } else {
            error_log('creating authorization url');
            $authUrl = $client->createAuthUrl();
            error_log($authUrl);
            return new JsonResponse(['success' => true, 'authUrl' => $authUrl]);
        }
        if ($client->getAccessToken()) {

            $_SESSION['access_token'] = $client->getAccessToken();
         
            // Prepare the message in message/rfc822
            try {
                $service = new Gmail($client);
                $optParams = [];
                $optParams['maxResults'] = 5; // Return Only 5 Messages
                $optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
                $messages = $service->users_messages->listUsersMessages('me',$optParams);
                $list = $messages->getMessages();
                $messageId = $list[0]->getId(); // Grab first Message
                
                
                $optParamsGet = [];
                $optParamsGet['format'] = 'full'; // Display message in payload
                $message = $service->users_messages->get('me',$messageId,$optParamsGet);
                $messagePayload = $message->getPayload();
                $headers = $message->getPayload()->getHeaders();
                $parts = $message->getPayload()->getParts();
                
                $body = $parts[0]['body'];
                $rawData = $body->data;
                $sanitizedData = strtr($rawData,'-_', '+/');
                $decodedMessage = base64_decode($sanitizedData);
                return new JsonResponse(['success' => true, 'message' => $decodedMessage]);
            } catch(Exception $e) {
                error_log('in exception handler');
                error_log($e);                
                return new JsonResponse(['success' => false, 'error' => $e->__toString()]);
            }
        }
        return new JsonResponse(['success' => false]);
    }
}

My twig template...

{% extends 'base.html.twig' %}

{% block title %}GMail API Bench{% endblock %}

{% block body %}
<div class="container m-5">
    <div class="row my-2">
        <div class="col-12">
            <button type="button" class="btn btn-primary btn-lg" id="test-gmail-button">Test GMail API</button>
        </div>
    </div>
    <div class="row my-2">
        <h4><b>Authorization:</b></h4>
        <div id="test-authorization">
            <a id="authorization-link" href="#"></a>
        </div>
        <input type="hidden" id="gmail-authorization-code" value="{{ code }}">
        {% if code is not null %}
            <span class="text-success"><h4>Authorized</h4></span>
        {% endif %}
    </div>
    <div class="row my-2">
        <h4><b>Results:</b></h4>
        <div id="test-results">
        </div>
    </div>
</div>

{% endblock %}

{% block javascripts %}
    <script src="/static/site/js/gmail_bench.js?v=1.20230126"></script>
{% endblock %}

My client-side JavaScript...

$(document).ready(() => {
    console.log('gmail_bench.js: in document ready')
})

$('#test-gmail-button').on('click', function(ev) {
    console.log('test gmail');
    let code = $('#gmail-authorization-code').val();
    $.ajax({
        url: '/g/mail/test',
        type: 'POST',
        data: {
            code: code
        },
        success: function(data, textStatus) {
            if(data.success) {
                if(data.authUrl) {
                    $('#authorization-link').attr('href',data.authUrl);
                    $('#authorization-link').html('Authorize');
                }
                if(data.message) {
                    $('#test-results').empty().append(data.message);
                }
            } else {
                $('#test-results').empty().append(data.error);
            }
        },
        error: function(xhr, textStatus) {
            console.log('in test gmail error');
            console.log(xhr);
            console.log(textStatus);
        }
    })  
})

So the way this works is the first post to the test endpoint returns the authorization url. This is added as a link on the page...

After initial test click...authorize link appears

Then after authorization, the OAuth2 code is added to the page...

After authorization

Finally the second click on test butter sends the code and the email contents come back...

After 2nd click of test button

Upvotes: 0

Jun Hsieh
Jun Hsieh

Reputation: 1614

This is the sample code I used to develop an email ticketing system. It shows how to retrieve labels, messages, and headers.

<?php

require_once __DIR__ . '/vendor/autoload.php';

define('APPLICATION_NAME', 'Gmail API PHP Quickstart');
define('CREDENTIALS_PATH', '~/.credentials/gmail-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_secret.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-php-quickstart.json
define('SCOPES', implode(' ', array(
  Google_Service_Gmail::GMAIL_READONLY)
));

if (php_sapi_name() != 'cli') {
  throw new Exception('This application must be run on the command line.');
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient() {
  $client = new Google_Client();
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES);
  $client->setAuthConfig(CLIENT_SECRET_PATH);
  $client->setAccessType('offline');

  // Load previously authorized credentials from a file.
  $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
  if (file_exists($credentialsPath)) {
    $accessToken = json_decode(file_get_contents($credentialsPath), true);
  } else {
    // Request authorization from the user.
    $authUrl = $client->createAuthUrl();
    printf("Open the following link in your browser:\n%s\n", $authUrl);
    print 'Enter verification code: ';
    $authCode = trim(fgets(STDIN));

    // Exchange authorization code for an access token.
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

    // Store the credentials to disk.
    if(!file_exists(dirname($credentialsPath))) {
      mkdir(dirname($credentialsPath), 0700, true);
    }
    file_put_contents($credentialsPath, json_encode($accessToken));
    printf("Credentials saved to %s\n", $credentialsPath);
  }
  $client->setAccessToken($accessToken);

  // Refresh the token if it's expired.
  if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
  }
  return $client;
}

/**
 * Expands the home directory alias '~' to the full path.
 * @param string $path the path to expand.
 * @return string the expanded path.
 */
function expandHomeDirectory($path) {
  $homeDirectory = getenv('HOME');
  if (empty($homeDirectory)) {
    $homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
  }
  return str_replace('~', realpath($homeDirectory), $path);
}

/**
 * Get list of Messages in user's mailbox.
 *
 * @param  Google_Service_Gmail $service Authorized Gmail API instance.
 * @param  string $userId User's email address. The special value 'me'
 * can be used to indicate the authenticated user.
 * @return array Array of Messages.
 */
function listMessages($service, $userId, $optArr = []) {
  $pageToken = NULL;
  $messages = array();
  do {
    try {
      if ($pageToken) {
        $optArr['pageToken'] = $pageToken;
      }
      $messagesResponse = $service->users_messages->listUsersMessages($userId, $optArr);
      if ($messagesResponse->getMessages()) {
        $messages = array_merge($messages, $messagesResponse->getMessages());
        $pageToken = $messagesResponse->getNextPageToken();
      }
    } catch (Exception $e) {
      print 'An error occurred: ' . $e->getMessage();
    }
  } while ($pageToken);

  return $messages;
}

function getHeaderArr($dataArr) {
    $outArr = [];
    foreach ($dataArr as $key => $val) {
        $outArr[$val->name] = $val->value;
    }
    return $outArr;
}

function getBody($dataArr) {
    $outArr = [];
    foreach ($dataArr as $key => $val) {
        $outArr[] = base64url_decode($val->getBody()->getData());
        break; // we are only interested in $dataArr[0]. Because $dataArr[1] is in HTML.
    }
    return $outArr;
}

function base64url_decode($data) {
  return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

function getMessage($service, $userId, $messageId) {
  try {
    $message = $service->users_messages->get($userId, $messageId);
    print 'Message with ID: ' . $message->getId() . ' retrieved.' . "\n";

    return $message;
  } catch (Exception $e) {
    print 'An error occurred: ' . $e->getMessage();
  }
}

function listLabels($service, $userId, $optArr = []) {
    $results = $service->users_labels->listUsersLabels($userId);

    if (count($results->getLabels()) == 0) {
      print "No labels found.\n";
    } else {
      print "Labels:\n";
      foreach ($results->getLabels() as $label) {
        printf("- %s\n", $label->getName());
      }
    }
}

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Gmail($client);
$user = 'me';

// Print the labels in the user's account.
listLabels($service, $user);

// Get the messages in the user's account.
$messages = listMessages($service, $user, [
    #'maxResults' => 20, // Return 20 messages.
    'labelIds' => 'INBOX', // Return messages in inbox.
]);

foreach ($messages as $message) {
    print 'Message with ID: ' . $message->getId() . "\n";

    $msgObj = getMessage($service, $user, $message->getId());

    $headerArr = getHeaderArr($msgObj->getPayload()->getHeaders());

    echo 'Message-ID: ' . $headerArr['Message-ID'];
    echo "\n";
    echo 'In-Reply-To: ' . (empty($headerArr['In-Reply-To']) ? '' : $headerArr['In-Reply-To']);
    echo "\n";
    echo 'References: ' . (empty($headerArr['References']) ? '': $headerArr['References']);
    echo "\n";

    #print_r($headerArr);

    $bodyArr = getBody($msgObj->getPayload()->getParts());
    echo 'Body: ' . (empty($bodyArr[0]) ? '' : $bodyArr[0]);
}

Reference:

https://developers.google.com/gmail/api/quickstart/php https://developers.google.com/gmail/api/v1/reference/users/messages/modify#php

Upvotes: 3

Muffy
Muffy

Reputation: 421

For the sake of demonstration, you can do something like this:

$optParams = [];
$optParams['maxResults'] = 5; // Return Only 5 Messages
$optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
$messages = $service->users_messages->listUsersMessages('me',$optParams);
$list = $messages->getMessages();
$messageId = $list[0]->getId(); // Grab first Message


$optParamsGet = [];
$optParamsGet['format'] = 'full'; // Display message in payload
$message = $service->users_messages->get('me',$messageId,$optParamsGet);
$messagePayload = $message->getPayload();
$headers = $message->getPayload()->getHeaders();
$parts = $message->getPayload()->getParts();

$body = $parts[0]['body'];
$rawData = $body->data;
$sanitizedData = strtr($rawData,'-_', '+/');
$decodedMessage = base64_decode($sanitizedData);

var_dump($decodedMessage);

Upvotes: 26

Samphors
Samphors

Reputation: 530

This is the full function, You can use it because It worked fine.

session_start();
$this->load->library('google');
$client = new Google_Client();
$client->setApplicationName('API Project');
$client->setScopes(implode(' ', array(Google_Service_Gmail::GMAIL_READONLY)));
//Web Applicaion (json)
$client->setAuthConfigFile('key/client_secret_105219sfdf2456244-bi3lasgl0qbgu5hgedg9adsdfvqmds5c0rkll.apps.googleusercontent.com.json');

$client->setAccessType('offline');       

// Redirect the URL after OAuth
if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $_SESSION['access_token'] = $client->getAccessToken();
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}

// If Access Toket is not set, show the OAuth URL
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
    $client->setAccessToken($_SESSION['access_token']);
} else {
    $authUrl = $client->createAuthUrl();
}

if ($client->getAccessToken()) {

    $_SESSION['access_token'] = $client->getAccessToken();
 
    // Prepare the message in message/rfc822
    try {
 
        // The message needs to be encoded in Base64URL

        $service = new Google_Service_Gmail($client);

        $optParams = [];
        $optParams['maxResults'] = 5; // Return Only 5 Messages
        $optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
        $messages = $service->users_messages->listUsersMessages('me',$optParams);
        $list = $messages->getMessages();
        $messageId = $list[0]->getId(); // Grab first Message


        $optParamsGet = [];
        $optParamsGet['format'] = 'full'; // Display message in payload
        $message = $service->users_messages->get('me',$messageId,$optParamsGet);
        $messagePayload = $message->getPayload();
        $headers = $message->getPayload()->getHeaders();
        $parts = $message->getPayload()->getParts();

        $body = $parts[0]['body'];
        $rawData = $body->data;
        $sanitizedData = strtr($rawData,'-_', '+/');
        $decodedMessage = base64_decode($sanitizedData);

        var_dump($decodedMessage);
 
    } catch (Exception $e) {
        print($e->getMessage());
        unset($_SESSION['access_token']);
    }
 
}

// If there is no access token, there will show url
if ( isset ( $authUrl ) ) { 
    echo $authUrl;
}

Upvotes: 12

Arthur Thompson
Arthur Thompson

Reputation: 9225

I'd start here: https://developers.google.com/gmail/api/v1/reference/users/messages/list and https://developers.google.com/gmail/api/v1/reference/users/messages/get

note that when you get a list of messages only the IDs of those messages are returned then you use the ID with the get method to actually get the message content:

Upvotes: 2

Related Questions