How to Send Email using Gmail API in PHP

When it comes to a website, you have to send emails to the users for many reasons. PHP provides a mail() function to send emails but there are limitations to it. Using this method, your emails most probably end up in spam. The reason is your hosting set the FROM email address to their system-generated email ID. This email address doesn’t look like a real email so email clients(like Gmail) mostly consider these incoming emails as spam.

In the real world, we hardly check spam. And if your emails are ending up in spam, your users will probably be missing your important emails. You’ll never appreciate it as it loses your business.

To resolve this problem, you can go for the SMTP server. But, SMTP server also has one drawback. While integrating SMTP, you need to pass your login details in plain text format. This can create a security problem. If your server gets compromised, your login credentials will get exposed.

Instead of going for the SMTP server, I’d recommend using the Gmail API which adds extra security. The Gmail API requires you to follow OAuth 2.0 instead of your login credentials. Once you complete the Google OAuth authentication, it generates the access token which will be used to send your website emails.

In this article, we study how to integrate Gmail API with the Symfony Mailer library. The Symfony Mailer is a component-based library for sending emails from PHP applications. It allows you to integrate third-party providers like Google to send your emails.

That being said, let’s take a look at how to send email using Gmail API in PHP.

Register an Application and Create Credentials

You first need to grab your OAuth client id and client secret. These credentials are required to build the Google OAuth flow.

Follow the steps below to get your keys.

  • Go to the Google Developer Console.
  • Create a new project. You can also select an existing project.
  • Add a name to your project. Google Console will generate a unique Project ID for it.
  • Your project will appear on top of the left sidebar.
  • Click on Library. You will see a list of Google APIs.
  • Enable Gmail API.
  • Click on the Credentials. Select Oauth Client id under Create credentials. Choose the radio button for the Web Application.
  • Give the Name. In the ‘Authorized redirect URIs’ add the link of the redirect URL. In my case, I passed the URL http://localhost/mailer/callback.php
  • Click on the Create button. You will get a client ID and client secret in the pop-up. Copy these details. We will need it in a moment.
gmail-api-redirect-url

Basic Configuration

As we are going to generate an access token, it should store in the database for later use. Each time your application sends an email, you need to fetch this access token and use it in the code.

Let’s create a database table using the following SQL.

CREATE TABLE `oauth_tokens` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `provider` varchar(255) NOT NULL,
  `provider_value` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Next, create a DB class that will interact with the database to retrieve, store, and update token information in the table.

class-db.php

<?php
class DB {
    private $dbHost     = "DB_HOST";
    private $dbUsername = "DB_USERNAME";
    private $dbPassword = "DB_PASSWORD";
    private $dbName     = "DB_NAME";
      
    public function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost, $this->dbUsername, $this->dbPassword, $this->dbName);
            if($conn->connect_error){
                die("Failed to connect with MySQL: " . $conn->connect_error);
            }else{
                $this->db = $conn;
            }
        }
    }
 
    public function is_table_empty() {
        $result = $this->db->query("SELECT id FROM oauth_tokens WHERE provider = 'google'");
        if($result->num_rows) {
            return false;
        }
    
        return true;
    }

    public function get_access_token() {
        $sql = $this->db->query("SELECT provider_value FROM oauth_tokens WHERE provider='google'");
        $result = $sql->fetch_assoc();
        return json_decode($result['provider_value']);
    }
    
    public function get_refresh_token() {
        $result = $this->get_access_token();
        return $result->refresh_token;
    }
    
    public function update_access_token($token) {
        if($this->is_table_empty()) {
            $sql = sprintf("INSERT INTO oauth_tokens(provider, provider_value) VALUES('%s', '%s')", 'google', $this->db->real_escape_string($token));
            $this->db->query($sql);
        } else {
            $sql = sprintf("UPDATE oauth_tokens SET provider_value = '%s' WHERE provider = '%s'", $this->db->real_escape_string($token), 'google');
            $this->db->query($sql);
        }
    }
}

To accomplish the end goal, in addition to the database, you will require the below packages.

Install these packages using the following commands.

composer require symfony/mailer
composer require symfony/google-mailer
composer require hybridauth/hybridauth

Generate OAuth Access Token for Gmail API

You have installed the HybridAuth library which will help to generate an access token. For this, you have to set up the configuration provided for Google service. Create a config.php file and add the below code to it.

<?php
require_once 'vendor/autoload.php';
require_once 'class-db.php';
 
define('GOOGLE_CLIENT_ID', 'PASTE_CLIENT_ID_HERE');
define('GOOGLE_CLIENT_SECRET', 'PASTE_CLIENT_SECRET_HERE');
 
$config = [
    'callback' => 'YOUR_DOMAIN_URL/callback.php',
    'keys'     => [
        'id' => GOOGLE_CLIENT_ID,
        'secret' => GOOGLE_CLIENT_SECRET
    ],
    'scope'    => 'https://mail.google.com',
    'authorize_url_parameters' => [
        'approval_prompt' => 'force', // to pass only when you need to acquire a new refresh token.
        'access_type' => 'offline'
    ]
];
 
$adapter = new Hybridauth\Provider\Google( $config );

Note that I passed the scope https://mail.google.com which is required to get the access token for Gmail API.

The callback.php file will automatically perform the authorization process and store the access token in the database table.

<?php
require_once 'config.php';

try {
    $adapter->authenticate();
    $token = $adapter->getAccessToken();
    $db = new DB();
    $db->update_access_token(json_encode($token));
    echo "Access token inserted successfully.";
}
catch( Exception $e ){
    echo $e->getMessage() ;
}

Go to the browser, run the YOUR_DOMAIN_URL/callback.php, complete the authentication and you should get your access token in your oauth_tokens table.

Send Email using Gmail API in PHP

Once you get the access token, you’re ready to use Gmail API to send your emails. All you need to do is grab the token from the database, build transport for Symfony Mailer, and shoot the emails.

Using Symfony Mailer, with the combination of your Google email and access token, your emails will be sent through Gmail API.

In the code below we are going to perform the following steps.

  • Get the access token from the Database.
  • Set up a Symfony transport to use Gmail API.
  • If the access token is expired, regenerate it in the background using a refresh token.
  • Store newly created access token in the database.
  • Send the Email.
<?php
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

send_email_to_user('ADD_RECIPIENT_EMAIL');

function send_email_to_user($email) {
    require_once 'config.php';

    $db = new DB();
    $arr_token = (array) $db->get_access_token();

    try {
        $transport = Transport::fromDsn('gmail+smtp://'.urlencode('GOOGLE_EMAIL').':'.urlencode($arr_token['access_token']).'@default');

        $mailer = new Mailer($transport);

        $message = (new Email())
            ->from('SENDER_NAME <SENDER_EMAIL>')
            ->to($email)
            ->subject('Email through Gmail API')
            ->html('<h2>Email sent through Gmail API</h2>');

        // Send the message
        $mailer->send($message);

        echo 'Email sent successfully.';
    } catch (Exception $e) {
        if( in_array($e->getCode(), ['535', '334']) ) {
            $refresh_token = $db->get_refresh_token();

            $response = $adapter->refreshAccessToken([
                "grant_type" => "refresh_token",
                "refresh_token" => $refresh_token,
                "client_id" => GOOGLE_CLIENT_ID,
                "client_secret" => GOOGLE_CLIENT_SECRET,
            ]);
            
            $data = (array) json_decode($response);
            $data['refresh_token'] = $refresh_token;

            $db->update_access_token(json_encode($data));

            send_email_to_user($email);
        } else {
            echo $e->getMessage(); //print the error
        }
    }
}

Make sure to replace the placeholders with their actual values. Here, I used the single parameter in the method send_email_to_user. You can pass more parameters(like cc, bcc) as per your flow. The basic code would remain the same.

I hope you understand sending emails using Gmail API with Symfony Mailer in PHP. With this approach, you can build a reliable system for emails and avoid directly using your login credentials. Give it a try and share your thoughts in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

11 thoughts on “How to Send Email using Gmail API in PHP

  1. Notice: Undefined property: stdClass::$refresh_token

    Fatal error: Uncaught Hybridauth\Exception\HttpRequestFailedException: Unable to refresh the access token. HTTP error 400. Raw Provider API response: { “error”: “invalid_request”, “error_description”: “Missing required parameter: refresh_token” }

    How to resolve the above issues

  2. i have question
    how to fill this part
    $transport = Transport::fromDsn(‘gmail+smtp://’.urlencode(‘GOOGLE_EMAIL’).’:’.urlencode($arr_token[‘access_token’]).’@default’);
    i have no any idea please help me ..

  3. on the send Email page there is a $adapter->refreshAccessToken <- this stuff, I wrote everything what you coded. However, the adapter is the undefined variable. I need some help on that one.
    Thanks a lot

    1. 15. urlencode(‘GOOGLE_EMAIL’) should change GOOGLE_EMAIL to the email address you activated the API on.
      20. ->from(‘SENDER_NAME ‘) change SENDER_EMAIL to the same old email address

    2. I had the same problem, in the catch part it calls the same function (recursive) see line 45 above. Somehow if it fails and then calls himself again then he somehow lost the value of $adapter. My error was that i forgot to change line 15: ‘GOOGLE_EMAIL’ to ‘myownemail@gmail.com’ and then again on line 20: ->from(‘SENDER_NAME ‘) to ->from(‘myownemail ‘) even though this fixed it for me.. the recursive still fails so might your token be expired you still want to paste the content of the TRY{} instead of the recursive call on line 45

      https://imgur.com/a/N3hDM0o

    1. Technically, if it’s working on a local server, it should be working on a live server. Did you turn on PHP debug mode? It gives an idea about errors and you can track them.

Leave a Reply

Your email address will not be published. Required fields are marked *