How to Send Email using Gmail API with PHPMailer

Emails are essentials for any website. Using emails you can interact with the users for various reasons. You can acknowledge them for some actions, urge them to come back on the website by promoting some exciting offers, keep them in the loop by sending new updates, information, etc.

When it comes to PHP-powered websites, to send an email mail() function comes by default in the core. You can use this method as follows.

<?php
$to = 'nobody@example.com';
$subject = 'the subject';
$message = 'hello';
$headers = array(
    'From' => 'webmaster@example.com',
    'Reply-To' => 'webmaster@example.com',
    'X-Mailer' => 'PHP/' . phpversion()
);
// To send HTML mail, the Content-type header must be set
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'Content-type: text/html; charset=iso-8859-1';

mail($to, $subject, $message, $headers);

Isn’t it easy? Unfortunately, there are some limitations using the mail() function.

  • It’s hard to send attachments in an email.
  • Your emails most probably end up in spam.
  • Couldn’t work if the server is not configured correctly.

SMTP Server

The user can easily overcome the above limitations by using the SMTP server. An SMTP(Simple Mail Transfer Protocol) server is an application used to send outgoing mail between email senders and receivers.

For PHP applications, you can use PHPMailer and Swift Mailer libraries that allow you to send emails through SMTP servers.

The SMTP server would fix all drawbacks mentioned above. However, they also have issues when it comes to security.

In most cases, while using an SMTP server you need to pass the login credentials. If you intend to use Gmail SMTP, Hosting provided SMTP then you have to pass your login information – username, password. Now, this leads to a major security threat if your server gets hacked. The hacker would then get your login details.

There are some providers like Mailjet that give you separate API keys instead of login credentials for SMTP servers.

One can choose those providers. But it requires you to enroll in their service. Most of them provide a free plan for the limited emails that can be sent. Based on your requirement, you can go for either free or premium plans.

But as a developer, we should be looking for free and reliable services. And to perform this email task, I’d recommend using Google APIs. Apart from the Gmail SMTP server, Google also provides Gmail XOAUTH2. And with the combination of PHPMailer and Gmail XOAUTH2, we can send our application emails free of cost.

PHPMailer

The PHPMailer is one of the most popular libraries used for sending emails from PHP applications. Popular CMS like WordPress, Drupal, Joomla uses this library under the hood for their emails.

Let’s install this library using the below command:

composer require phpmailer/phpmailer

Later, we also need to deal with Google OAuth. To handle it, install the league/oauth2-google library.

composer require league/oauth2-google

Upon installing libraries, copy vendor/phpmailer/phpmailer/get_oauth_token.php and paste them into the project root directory. We will require this file to complete the Google OAuth flow and grab the refresh token.

Now to complete the Google OAuth flow, we need to register the application, get credentials. While registering, it requires setting an Authorized redirect URL. Here, we will use the path of get_oauth_token.php file. Let’s say this path is http://localhost/artisansweb/get_oauth_token.php .

Note: If someone wants to do the same task using the Swift Mailer library, then refer to our article How to Send Email using Gmail API in PHP.

Register an Application with Google

Follow the steps below to registering an application with Google and copy your client id and client secret.

  • 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 Web Application.
  • Give the Name. Under Authorized JavaScript origins enter your domain URL. In the ‘Authorized redirect URIs’ add the link of the redirect URL. In my case, I passed the URL http://localhost/artisansweb/get_oauth_token.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_xoauth2

Basic Configuration

The PHPMailer library requires an OAuth refresh token in their configuration. So, it is better to store it in a database. Run the below SQL query into your database and create a table ‘tokens’.

CREATE TABLE `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;

Now, to interact with this database table let’s create a DB class that will insert/update, and fetch the refresh token.

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_token_empty() {
        $result = $this->db->query("SELECT id FROM tokens WHERE provider = 'google'");
        if($result->num_rows) {
            return false;
        }
 
        return true;
    }

    public function get_refersh_token() {
        $sql = $this->db->query("SELECT provider_value FROM tokens WHERE provider='google'");
        return $sql->fetch_assoc()['provider_value'];
    }

    public function update_refresh_token($token) {
        if($this->is_token_empty()) {
            $this->db->query("INSERT INTO tokens(provider, provider_value) VALUES('google', '$token')");
        } else {
            $this->db->query("UPDATE tokens SET provider_value = '$token' WHERE provider = 'google'");
        }
    }
}

Generate OAuth Refresh Token for Gmail API

In the previous steps, we have copied get_oauth_token.php in the root directory. This file will give us a refresh token. But, as we need to store the refresh token, I am including class-db.php and the code for token insertion into it.

get_oauth_token.php

<?php

/**
 * PHPMailer - PHP email creation and transport class.
 * PHP Version 5.5
 * @package PHPMailer
 * @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
 * @author Brent R. Matzelle (original founder)
 * @copyright 2012 - 2020 Marcus Bointon
 * @copyright 2010 - 2012 Jim Jagielski
 * @copyright 2004 - 2009 Andy Prevost
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
 * @note This program is distributed in the hope that it will be useful - WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 */

/**
 * Get an OAuth2 token from an OAuth2 provider.
 * * Install this script on your server so that it's accessible
 * as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
 * e.g.: http://localhost/phpmailer/get_oauth_token.php
 * * Ensure dependencies are installed with 'composer install'
 * * Set up an app in your Google/Yahoo/Microsoft account
 * * Set the script address as the app's redirect URL
 * If no refresh token is obtained when running this file,
 * revoke access to your app and run the script again.
 */

namespace PHPMailer\PHPMailer;

/**
 * Aliases for League Provider Classes
 * Make sure you have added these to your composer.json and run `composer install`
 * Plenty to choose from here:
 * @see http://oauth2-client.thephpleague.com/providers/thirdparty/
 */
//@see https://github.com/thephpleague/oauth2-google
use League\OAuth2\Client\Provider\Google;
//@see https://packagist.org/packages/hayageek/oauth2-yahoo
use Hayageek\OAuth2\Client\Provider\Yahoo;
//@see https://github.com/stevenmaguire/oauth2-microsoft
use Stevenmaguire\OAuth2\Client\Provider\Microsoft;

if (!isset($_GET['code']) && !isset($_GET['provider'])) {
    ?>
<html>
<body>Select Provider:<br>
<a href='?provider=Google'>Google</a><br>
<a href='?provider=Yahoo'>Yahoo</a><br>
<a href='?provider=Microsoft'>Microsoft/Outlook/Hotmail/Live/Office365</a><br>
</body>
</html>
    <?php
    exit;
}

require 'vendor/autoload.php';
require_once 'class-db.php';

session_start();

$providerName = '';

if (array_key_exists('provider', $_GET)) {
    $providerName = $_GET['provider'];
    $_SESSION['provider'] = $providerName;
} elseif (array_key_exists('provider', $_SESSION)) {
    $providerName = $_SESSION['provider'];
}
if (!in_array($providerName, ['Google', 'Microsoft', 'Yahoo'])) {
    exit('Only Google, Microsoft and Yahoo OAuth2 providers are currently supported in this script.');
}

//These details are obtained by setting up an app in the Google developer console,
//or whichever provider you're using.
$clientId = 'GOOGLE_CLIENT_ID';
$clientSecret = 'GOOGLE_CLIENT_SECRET';

//If this automatic URL doesn't work, set it yourself manually to the URL of this script
$redirectUri = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
//$redirectUri = 'http://localhost/PHPMailer/redirect';

$params = [
    'clientId' => $clientId,
    'clientSecret' => $clientSecret,
    'redirectUri' => $redirectUri,
    'accessType' => 'offline'
];

$options = [];
$provider = null;

switch ($providerName) {
    case 'Google':
        $provider = new Google($params);
        $options = [
            'scope' => [
                'https://mail.google.com/'
            ]
        ];
        break;
    case 'Yahoo':
        $provider = new Yahoo($params);
        break;
    case 'Microsoft':
        $provider = new Microsoft($params);
        $options = [
            'scope' => [
                'wl.imap',
                'wl.offline_access'
            ]
        ];
        break;
}

if (null === $provider) {
    exit('Provider missing');
}

if (!isset($_GET['code'])) {
    //If we don't have an authorization code then get one
    $authUrl = $provider->getAuthorizationUrl($options);
    $_SESSION['oauth2state'] = $provider->getState();
    header('Location: ' . $authUrl);
    exit;
    //Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
    unset($_SESSION['oauth2state']);
    unset($_SESSION['provider']);
    exit('Invalid state');
} else {
    unset($_SESSION['provider']);
    //Try to get an access token (using the authorization code grant)
    $token = $provider->getAccessToken(
        'authorization_code',
        [
            'code' => $_GET['code']
        ]
    );
    //Use this to interact with an API on the users behalf
    //Use this to get a new access token if the old one expires
    //echo 'Refresh Token: ', $token->getRefreshToken();

    $db = new \DB();
    if($db->is_token_empty()) {
        $db->update_refresh_token($token->getRefreshToken());
        echo "Refresh token inserted successfully.";
    }
}

Before running this file, make sure you have passed your Google client ID and Google client secret to the variables $clientId and $clientSecret respectively.

Send Email using Gmail API with PHPMailer

We are now ready with our refresh token and Google app credentials. Next, using the code provided by the PHPMailer library we can send our emails as follows.

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;


require_once 'vendor/autoload.php';
require_once 'class-db.php';

$mail = new PHPMailer();
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->Port = 465;

//Set the encryption mechanism to use:
// - SMTPS (implicit TLS on port 465) or
// - STARTTLS (explicit TLS on port 587)
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;

$mail->SMTPAuth = true;
$mail->AuthType = 'XOAUTH2';

$email = 'GOOGLE_EMAIL'; // the email used to register google app
$clientId = 'GOOGLE_CLIENT_ID';
$clientSecret = 'GOOGLE_CLIENT_SECRET';

$db = new DB();
$refreshToken = $db->get_refersh_token();

//Create a new OAuth2 provider instance
$provider = new Google(
    [
        'clientId' => $clientId,
        'clientSecret' => $clientSecret,
    ]
);

//Pass the OAuth provider instance to PHPMailer
$mail->setOAuth(
    new OAuth(
        [
            'provider' => $provider,
            'clientId' => $clientId,
            'clientSecret' => $clientSecret,
            'refreshToken' => $refreshToken,
            'userName' => $email,
        ]
    )
);

$mail->setFrom($email, 'FROM_NAME');
$mail->addAddress('RECIPIENT_EMAIL', 'RECIPIENT_NAME');
$mail->isHTML(true);
$mail->Subject = 'Email Subject';
$mail->Body = '<b>Email Body</b>';

//send the message, check for errors
if (!$mail->send()) {
    echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
    echo 'Message sent!';
}

Make sure to replace placeholders with the actual values in the above code. Upon running this code, the recipient should receive an email.

I hope you understand sending emails using Gmail API with PHPMailer. I would like to hear your thoughts and suggestions in the comment section below.

Related Articles

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

2 thoughts on “How to Send Email using Gmail API with PHPMailer

Leave a Reply

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