Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tut] Sending email using PhpMailer with Gmail XOAUTH2

#1
Sending email using PhpMailer with Gmail XOAUTH2

by Vincy. Last modified on April 18th, 2021.

Are you keeping your email password in a PHP file as plain text? If your server is compromised, what will happen to your emails? This article is for you.

When people consult for building application components for sending emails, my first focus will be on security. Of course, it is a classic example where application developers must cover security.

Though PHP has a built-in mail function mail(), I have looked for a better way of doing this. It’s about guaranteeing dependable security while configuring email sending services on a customer’s application.

PHPMailer library as an unbeatable component of sending emails with advanced features. I used Google OAuth client to send email via PHPMailer in a secured way.

I have created a simple basic example here with this article to construct the email sending script. Let us get in for collecting more details about sending an email with PHPMailer via Gmail XOAUTH2.

What is inside?


  1. About this example
  2. Dependencies and installation commands
  3. Generate API keys and refresh token
  4. UI template and client-side validation
  5. PHP controller calls mail sending script 
  6. Application configurable directives
  7. Mail service using PhpMailer and Gmail XOAUTH2

About this example


This example is for creating a mailing service to send email via PHPMailer using Google OAuth client.

It shows a contact form to the user to enter the details. The form submit action sends the contact email to the recipient. If you want a secured contact form component, get Iris.

The required dependencies are installed via composer and integrated into this example to send an email.

The application configurations set the keys to request token-based authentication while sending mails.

It covers not only the mail sending but also an end-to-end working contact form component.

The following image shows the file structure of this example. The vendor directory is expanded to display the dependencies required for this code.

Contact Form OAuth Email Files

Dependencies and installation commands


As we mentioned in the introductory part, this code uses PHPMailer and the OAuth client library.

The dependent libraries required are downloaded automatically by installing these two pages via a package management tool like the composer.

Command to install the PHPMailer via composer is,

composer require phpmailer/phpmailer

To use Google OAuth, then run this command to download the dependencies shown in the file structure image.

composer require league/oauth2-google

Generate API keys and refresh token


Here are the steps to create a Google API project and get the keys and the token. These keys are the parameters for the process of token-based authentication.

  1. Login to Google account and go to the cloud platform console.
  2. From the left sliding menu, navigate IAM & Admin -> Manage Resources. Click CREATE PROJECT and enter the details.
  3. Go to API & Services -> Library and enable Gmail API.
  4. Go to API & Services -> Credentials and click CREATE CREDENTIALS -> OAuth client ID.
  5. Choose the application type and fill in other details to generate the keys.

Generate Gmail API Keys and Token

After getting the keys, configure it into the following file that comes with the PHPMailer package. It is to get the refresh token.

vendor/phpmailer/phpmailer/get_oauth_token.php

The following code shows where to set client-id and client-secret keys to get the refresh token.


<?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/pr...hirdparty/ */
//@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'; 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 = 'RANDOMCHARS-----duv1n2.apps.googleusercontent.com';
$clientSecret = 'RANDOMCHARS-----lGyjPcRtvP'; //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();
}

UI template and client-side validation


This is a HTML code for a simple contact form template. It triggers form validation and the back-end mail sending script on submitting the form.

It is self-explanatory with usual form fields and semantic attributes.

index.php

<html>
<head>
<title>Contact Us Form</title>
<link rel="stylesheet" type="text/css" href="assets/css/style.css" />
</head>
<body> <div class="form-container"> <form name="frmContact" id="" frmContact"" method="post" action="" enctype="multipart/form-data" on‌submit="return validateContactForm()"> <div class="input-row"> <label style="padding-top: 20px;">Name</label> <span id="userName-info" class="info"></span><br /> <input type="text" class="input-field" name="userName" id="userName" /> </div> <div class="input-row"> <label>Email</label> <span id="userEmail-info" class="info"></span><br /> <input type="text" class="input-field" name="userEmail" id="userEmail" /> </div> <div class="input-row"> <label>Subject</label> <span id="subject-info" class="info"></span><br /> <input type="text" class="input-field" name="subject" id="subject" /> </div> <div class="input-row"> <label>Message</label> <span id="userMessage-info" class="info"></span><br /> <textarea name="content" id="content" class="input-field" cols="60" rows="6"></textarea> </div> <div> <input type="submit" name="send" class="btn-submit" value="Send" /> <div id="statusMessage"> <?php if (! empty($response)) { ?> <p class='<?php echo $response['type']; ?>Message'><?php echo $response['text']; ?></p> <?php } ?> </div> </div> </form> </div> <script type="text/javascript" src="assets/js/validation.js"></script>
</body>
</html>

The form validation functions restrict the form submit till getting not-empty values of all fields.

It validates the email field data if it matches the specified regex pattern.

assets/js/validation.js

function validateContactForm() { var emailRegex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; var userName = document.getElementById("userName").value; var userEmail = document.getElementById("userEmail").value; var subject = document.getElementById("subject").value; var content = document.getElementById("content").value; var valid = true; if (userName == "") { markAsInvalid("userName", "required"); document.getElementById("userName").classList.add("error-field"); valid = false; } else { markAsValid("userName"); document.getElementById("userName").classList.remove("error-field"); } if (userEmail == "") { markAsInvalid("userEmail", "required"); document.getElementById("userEmail").classList.add("error-field"); valid = false; } else if (!emailRegex.test(userEmail)) { markAsInvalid("userEmail", "invalid email address"); document.getElementById("userEmail").classList.add("error-field"); valid = false; } else { markAsValid("userEmail"); document.getElementById("userEmail").classList.remove("error-field"); } if (subject == "") { markAsInvalid("subject", "required"); document.getElementById("subject").classList.add("error-field"); valid = false; } else { markAsValid("subject"); document.getElementById("subject").classList.remove("error-field"); } if (content == "") { markAsInvalid("userMessage", "required"); document.getElementById("content").classList.add("error-field"); valid = false; } else { markAsValid("userMessage"); document.getElementById("content").classList.remove("error-field"); } return valid;
} function markAsValid(id) { document.getElementById(id + "-info").style.display = "none";
} function markAsInvalid(id, feedback) { document.getElementById(id + "-info").style.display = "inline"; document.getElementById(id + "-info").innerText = feedback;
}

PHP controller calls mail sending script


This script is added at the beginning of the index.php file above the contact form HTML.

It connects the PHP MailService to send the contact email using PHPMailer with XOAUTH2.

It captures the response of the mail sending process. It acknowledges the end-user to know if the contact message is received or not.

For sending emails with PHPMailer using GMail SMTP, the linked article has the download with suitable code.

index.php (PHP code to call mail service to send email)

<?php
namespace Phppot; require_once ("lib/MailService.php");
$mailService = new MailService();
if (! empty($_POST['send'])) { $response = $mailService->sendContactMail($_POST);
}
?>

Application configurable directives


This is the configuration file created for this example code. It defines the PHP constants to hold the keys and tokens generated earlier for authentication.

It also defines the recipient email addresses and OAuth user email and details.

lib/Config.php

<?php
/** * Copyright © Vincy - All Rights Reserved * Unauthorized copying of this file, via any medium is strictly prohibited * Proprietary and confidential * Written by Vincy <vincy@phppot.com> */
namespace Phppot; /** * This class contains the configuration options */
class Config
{ const SENDER_NAME = 'Vincy'; const SENDER_EMAIL = 'vincy@phppot.com'; // you can add one or more emails separated by a comma (,). const RECIPIENT_EMAIL = 'vincy@phppot.com'; const OAUTH_USER_EMAIL = 'vincy@phppot.com'; const OAUTH_CLIENT_ID = ''; const OAUTH_SECRET_KEY = ''; const REFRESH_TOKEN = ''; const SMTP_HOST = 'smtp.gmail.com'; const SMTP_PORT = 587;
}

Mail service using PhpMailer and Gmail XOAUTH2


The sendContactMail() function sets the contact form details to build the email body content.

It creates the PHPMailer instance and sets the attributes to authenticate the mail sending requests.

It sets the Google OAuth provider instance with the generated keys and token and the OAuth user details.

Then, it adds the routine mail attributes, the target email, mail-from, reply-to and more.

It constructs a JSON response to return the result of the mail sending process.

lib/MailService.php

<?php
namespace Phppot; use Phppot\Config;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; class MailService
{ function sendContactMail($postValues) { $name = $postValues["userName"]; $email = $postValues["userEmail"]; $subject = $postValues["subject"]; $content = $postValues["content"]; require_once __DIR__ . '/Config.php'; $recipientArray = explode(",", Config::RECIPIENT_EMAIL); require_once __DIR__ . '/../vendor/autoload.php'; $mail = new PHPMailer(true); // Comment the following lines of code till $mail->Port to send // mail using phpmail instead of smtp. $mail->isSMTP(); //Enable SMTP debugging //SMTP::DEBUG_OFF = off (for production use) //SMTP::DEBUG_CLIENT = client messages //SMTP::DEBUG_SERVER = client and server messages $mail->SMTPDebug = SMTP::DEBUG_OFF; //Set the hostname of the mail server $mail->Host = Config::SMTP_HOST; //Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission $mail->Port = Config::SMTP_PORT; //Set the encryption mechanism to use - STARTTLS or SMTPS $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Whether to use SMTP authentication $mail->SMTPAuth = true; //Set AuthType to use XOAUTH2 $mail->AuthType = 'XOAUTH2'; //Fill in authentication details here //Either the gmail account owner, or the user that gave consent $oauthUserEmail = Config::OAUTH_USER_EMAIL; $clientId = Config::OAUTH_CLIENT_ID; $clientSecret = Config::OAUTH_SECRET_KEY; //Obtained by configuring and running get_oauth_token.php //after setting up an app in Google Developer Console. $refreshToken = Config::REFRESH_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' => $oauthUserEmail, ] ) ); // Recipients $mail->setFrom(Config::SENDER_EMAIL, $name); $mail->addReplyTo($email, $name); $mail->addAddress(Config::RECIPIENT_EMAIL, Config::RECIPIENT_EMAIL); $mail->Subject = $subject; $mail->CharSet = PHPMailer::CHARSET_UTF8; $mail->msgHTML($mailBody); //Replace the plain text body with one created manually $mail->AltBody = 'This is a plain-text message body'; if (!$mail->send()) { $output = json_encode(array('type'=>'error', 'text' => '<b>'.$from.'</b> is invalid.')); $output = json_encode(array('type'=>'error', 'text' => 'Server error. Please mail vincy@phppot.com')); } else { $output = json_encode(array('type'=>'message', 'text' => 'Thank you, I will get back to you shortly.')); } return $output; }
}

Contact Form
This downloadable source is not with the dependent packages. Use composer to download the dependencies.
Download

↑ Back to Top



https://www.sickgaming.net/blog/2021/04/...l-xoauth2/
Reply



Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tut] Single Product eCommerce Website with Email Checkout in PHP xSicKxBot 0 29 04-22-2021, 05:00 PM
Last Post: xSicKxBot

Forum Jump:

[-]
Active Threads
News - F4F Reveals Banjo-Kazooie Mumbo J...
Last Post: xSicKxBot
Yesterday 11:16 PM
» Replies: 0
» Views: 3
News - Review Roundup For Spiral: From T...
Last Post: xSicKxBot
Yesterday 11:16 PM
» Replies: 0
» Views: 14
Black Ops 2 Box and Name ESP | Fully Ext...
Last Post: Jaesanta
Yesterday 10:34 PM
» Replies: 55
» Views: 20949
[Tut] [FANG KILLER ICP] Will the Interne...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 9
(Indie Deal) Star Wars, No Man's Sky, Co...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 10
Unity Mega Bundle 2021 On Now
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 11
Mobile - Noob Army Tycoon codes – free m...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 10
AppleInsider - UK repair firm fined $147...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 10
Microsoft - Securing a new world of hybr...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 9
Fedora - Using Ansible to configure Podm...
Last Post: xSicKxBot
Yesterday 05:04 PM
» Replies: 0
» Views: 10

[-]
Twitter

Copyright © SickGaming.net 2012-2020