When it comes to a website, we must send users emails for various reasons. PHP provides a mail() function, but it has limitations. Using this method, your emails most probably end up in spam. You’ll never like it. In the real world, we hardly check spam. If your emails go into spam, your users will probably miss your important emails.
To resolve this problem, we chose the SMTP server. However, it 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 can be exposed.
Instead of using the SMTP server, I recommend using the Gmail API, which adds extra security. The Gmail API requires you to follow the OAuth 2.0 flow instead of using your login credentials. Once you complete the Google OAuth steps, it generates the access token, which will be used to send your application emails.
This article studies integrating the 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 said, let’s examine how to send an email using the Gmail API in PHP.
Register an Application and Create Credentials
First, you 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 Credentials. Under Create credentials, select OAuth Client ID. Choose the radio button for Web Application.
- Give the Name. In the ‘Authorized redirect URIs’, add the redirect URL. In my case, I passed the URL
http://localhost/mailer/callback.php - Click on the Create button. A pop-up will appear with a client ID and client secret. Copy these details. We will need them in a moment.

Basic Configuration
As I mentioned before, we need to generate an access token. This token should be stored in the database for later use. Each time our application sends an email, we need to fetch and use it.
Let’s create a MySQL table using the following query.
| 123456 | CREATETABLE`google_oauth` ( `id` int(11) NOTNULLAUTO_INCREMENT, `provider` varchar(255) NOTNULL, `provider_value` text NOTNULL, PRIMARYKEY(`id`)) ENGINE=InnoDB DEFAULTCHARSET=utf8mb4; |
Next, create a DB class that interacts with the database and retrieves, stores, and updates token information in the table.
class-db.php
| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647495051525354555657585960616263646566 | <?phpclassDB { private$dbHost= "DB_HOST"; private$dbUsername= "DB_USERNAME"; private$dbPassword= "DB_PASSWORD"; private$dbName= "DB_NAME"; publicfunction__construct(){ if(!isset($this->db)){ // Connect to the database $conn= newmysqli($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; } }} publicfunctionis_token_empty() { $result= $this->db->query("SELECT id FROM google_oauth WHERE provider = 'google'"); if($result->num_rows) { returnfalse; } returntrue; } publicfunctionget_access_token() {$sql= $this->db->query("SELECT provider_value FROM google_oauth WHERE provider='google'"); $result= $sql->fetch_assoc(); returnjson_decode($result['provider_value']); } publicfunctionget_refersh_token() { $result= $this->get_access_token(); return$result->refresh_token; } publicfunctionupdate_access_token($token) { if($this->is_token_empty()) {$this->db->query("INSERT INTO google_oauth(provider, provider_value) VALUES('google', '$token')"); } else{$this->db->query("UPDATE google_oauth SET provider_value = '$token' WHERE provider = 'google'"); } }} |
We will require a few packages to accomplish our task. Those packages are – Symfony Mailer, Symfony’s Google Mailer, and HybridAuth. Install these packages using the commands below.
composer require symfony/mailer composer require symfony/google-mailer composer require hybridauth/hybridauth
Generate an OAuth Access Token for Gmail API
You have installed the HybridAuth library, which will generate an access token. For this, you have to follow their configuration setup. Create a config.php file and add the below code to it.
| 123456789101112131415161718192021 | <?phprequire_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= newHybridauth\Provider\Google( $config); |
You may have noticed I passed the scope https://mail.google.com which is required to get the access token for the Gmail API.
The the callback.php file will perform the authorization flow and store the access token in the database table.
| 12345678910111213 | <?phprequire_once'config.php';try{ $adapter->authenticate(); $token= $adapter->getAccessToken(); $db= newDB(); $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.phpComplete the authentication, and you should get your access token in your google_oauth table.
Send Email using Gmail API in PHP.
Once we get the access token, it becomes easy to use the Gmail API to send our emails. All we need to do is grab the token from the database, build transport for Symfony Mailer, and shoot the emails. Using Symfony Mailer, your emails will be sent through the Gmail API, using the combination of your Google email and access token.
In the code below, we are taking the following steps:
- Get the access token from the Database.
- Set up a transport to use the Gmail API.
- Regenerate the access token if it has expired using a refresh token.
- Store the newly created access token in the database.
- Send the Email.
[quads id=3]
| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 | <?phpuseSymfony\Component\Mailer\Transport;useSymfony\Component\Mailer\Mailer;useSymfony\Component\Mime\Email;send_email_to_user('ADD_RECIPIENT_EMAIL');functionsend_email_to_user($email) { require_once'config.php'; $db= newDB(); $arr_token= (array) $db->get_access_token(); try{ $transport= Transport::fromDsn('gmail+smtp://'.urlencode('GOOGLE_EMAIL').':'.urlencode($arr_token['access_token']).'@default'); $mailer= newMailer($transport); $message= (newEmail()) ->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( !$e->getCode() ) { $refresh_token= $db->get_refersh_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 } }} |
[quads id=3]
Make sure to replace the placeholders with their actual values. Here, I used the single parameter of email in the method send_email_to_user. You can change it as per your flow. The basic code would remain the same.
It’s all about sending emails using Gmail API with Symfony Mailer in PHP. This approach allows you to build a reliable system and avoid using your login credentials directly. Try it and share your thoughts and suggestions in the comment section below.
