how to send emails from localhost using PHP mailer with HTML Form

How to send email from localhost in PHP?

PHPMailer is a code library to send emails safely and easily via PHP code from a web server, and you can also send emails from localhost.

Here you will learn how to send emails using PHPMailer with Gmail SMTP and for authentication, we will use email and password and we will also see an example with the XOAUTH2 mechanism.

Sending emails using PHPMailer with “Email” and “Password”

Generate app password

First, you have to generate an App password for your Gmail.

So, log in to your Google account » Go to the security tab » Make sure that 2-step verification is enabled.

google account 2-step verification

Now, open the following link (make sure you are logged in), and generate an app password.

https://myaccount.google.com/apppasswords
select the app and device you want to generate the app password for
generate an app password

App password has been generated, copy the password –

app password has been generated, copy the password

After that, Install only the PHPMailer via composer on your project folder –

composer require phpmailer/phpmailer

Here is an example of how to use the PHPMailer to send emails with the Username and Password. Want to know more, read the official docs.

In the following code, change the details according to yours

<?php
require __DIR__ . "/vendor/autoload.php";

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

// Change the following details according to yours
$gmail = "[email protected]";
$app_password = "app_password";

$sender_name = "Sender Name";
$receiver_email = "[email protected]";
$mail_subject = "email subject";
$mail_body = "email body";

try {
    //Create an instance; passing `true` enables exceptions
    $mail = new PHPMailer(true);

    $mail->isSMTP();  //Send using SMTP

    //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_SERVER;

    $mail->Host = 'smtp.gmail.com'; //Set the SMTP server to send through

    //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
    $mail->Port = 587;

    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->SMTPAuth = true; //Whether to use SMTP authentication

    $mail->Username   = $gmail; //SMTP username
    $mail->Password   = $app_password; //SMTP password

    /** Set who the message is to be sent from
     *  For gmail, this generally needs to be the same as the user you logged * in as. */
    $mail->setFrom($gmail, $sender_name);


    // who will receive the email
    $mail->addAddress($receiver_email);
    // if you want to send email to multiple users, then add the email addresses you which you want to send.
    //$mail->addAddress('[email protected]');
    //$mail->addAddress('[email protected]');

    $mail->isHTML(true);
    $mail->Subject = $mail_subject; // Subject of the Email
    $mail->Body = $mail_body; // Mail Body

    //For Attachments
    //$mail->addAttachment('/var/tmp/file.tar.gz');  // Add attachments
    //$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // You can specify the file name

    $mail->send();
    echo "Email has been sent successfully.";
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Sending emails using PHPMailer with “XOAUTH2”

1. Create a folder inside the localhost directory, and name it whatever you want, I called it 📁 phpmailer.

2. Install the phpmailer and oauth2-google via composer inside the phpmailer directory.

 composer require phpmailer/phpmailer league/oauth2-google

3. Move the get_oauth_token.php to the root of the phpmailer folder.

get OAuth token PHP file inside the vendor folder
move the get OAuth token PHP file to the root
#from this
phpmailer/vendor/phpmailer/phpmailer/get_oauth_token.php

#to this
phpmailer/get_oauth_token.php

How to get Google Client ID and Secret for PHPMailer?

oauth2-google will not work without the client ID, Secret, and refresh token, so we have to generate these three things. Follow the below steps to generate the Client ID and Secret –

  1. Login to Google Cloud Console

    Go to the Google Cloud Console and login with your Google account.

  2. Create a New Project

    After login to your account, Go to Select a project » New Project » create a new project.
    google cloud console create new project

  3. Select the project and go to the APIs & Services

    Select the project and go to the APIs & Services

  4. Enable the Gmail API

    Enable the Gmail API

  5. Create Credentials

    Create Credentials

  6. Choose Web Application & enter the redirect URL

    Redirect URL will be the location of the get_oauth_token.php
    Choose Web Application & enter the redirect URL

  7. Collect your Client ID and Secret

    Collect your Client ID and Secret

  8. Get your Refresh Token

    Open the get_oauth_token.php in your browser, then add client ID and Secret and then click continue.
    http://localhost/phpmailer/get_oauth_token.php
    Get your Refresh Token for PHPMailer


4. After getting the Client-ID, Client-Secret, and refresh token, here is the PHP code to send emails

<?php
// Add your Client ID, Secret and Refresh token
$clientID = "654563609574-7f5a4c2ev************99m0i1.apps.googleusercontent.com";
$clientSecret = "GOCSPX-opn_K************NLMPB";
$refreshToken = "1//0g8Dng2fJk3AuC********NwF-L9IrQVKMzy6t***********sVCDSDEYCW2j8z*****nTYiXO3VzuthW-cico";
$email = '[email protected]';
$receiver_email = '[email protected]'; // Email-address of the recipient of the email

// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

// Load Composer's autoloader
require 'vendor/autoload.php';

// Create an instance; passing `true` enables exceptions
$mail = new PHPMailer(true);

try{
  $mail->isSMTP(); // Tell PHPMailer to use SMTP

// 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_SERVER;

  // Set the hostname of the mail server
  $mail->Host = 'smtp.gmail.com';
  
  // Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission
  $mail->Port = 587;

  // 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';

  // 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,
        ]
    )
  );

  /*
  * Set who the message is to be sent from
  * For gmail, this generally needs to be the same as the user you logged in as
  */
  $mail->setFrom($email, 'Name of the sender');

  $mail->addAddress($receiver_email);
  /* if you want to send email to multiple users, then add the email addresses you which you want to send. e.g -
  * $mail->addAddress('[email protected]');
  * $mail->addAddress('[email protected]');
  */

  $mail->isHTML(true); # Set email format to HTML
  $mail->Subject = "Subject Of the email";
  $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
  $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

  /*
  * For Attachments -
  * $mail->addAttachment('/var/tmp/file.tar.gz'); Add attachments
  * $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); You can specify the file name in the second parameter
  */

  // Call the send() method to send the mail.
  $mail->send();
  echo 'Message has been sent';
}
catch(Exception $e){
  echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Send emails using PHPMailer with HTML Form

Now we will see how to send emails using PHPMailer with HTML Form. Here is the Demo

Send emails using PHPMailer with HTML Form

In the same project folder (phpmailer) we have to make three files – send.php, index.php, and style.css

PHPMailer with html form folder structure

send.php file contains the send_mail() function used to send emails, this function has one parameter ($form_data) and takes form data as an array.

<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

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

function send_mail($form_data)
{
  // Put your client id, secret, refresh token, and email
  $clientID = "654563609574-7f5a*****oj0bt**0i1.apps.googleusercontent.com";
  $clientSecret = "GOCSPX-opn_K*********KNLMPB";
  $refreshToken = "1//0g8Dng2fJk3AuCgY*****GBASNwF-L9IrQV********LbUp6lDVatPsVCD*****TYiXO3VzuthW-cico";
  $sender_email = "[email protected]";

  $provider = new Google(
    [
        "clientId" => $clientID,
        "clientSecret" => $clientSecret,
    ]
  );

  $oAuth = new OAuth(
    [
        'provider' => $provider,
        'clientId' => $clientID,
        'clientSecret' => $clientSecret,
        'refreshToken' => $refreshToken,
        'userName' => $sender_email,
    ]
  );

  $mail = new PHPMailer(true);
  try {
    $mail->isSMTP();
    $mail->SMTPDebug = SMTP::DEBUG_OFF;
    $mail->Host = 'smtp.gmail.com';
    $mail->Port = 587;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->SMTPAuth = true;
    $mail->AuthType = 'XOAUTH2';
    $mail->setOAuth($oAuth);
    $mail->setFrom($sender_email, "Sender Name");
    $mail->addAddress($form_data["email"]);
    $mail->isHTML(true);
    $mail->Subject = $form_data["subject"];
    $mail->Body = $form_data["message"];

    // If there is any attachment to send
    if ($form_data["atch"]) {
      $mail->addAttachment($form_data["atch"]["tmp_name"], $form_data["atch"]["name"]);
    }
    $mail->send();
    return true;
  } catch (Exception $e) {
    return false;
  }
}

index.php contains the HTML form and here we will call the send_mail() function to send email, Other than it contains some validations –

<?php
require_once __DIR__ . "/send.php";
// This variables are for showing messages
$error = false;
$success = false;

if (
  isset($_POST["email"]) &&
  isset($_POST["subject"]) &&
  isset($_POST["message"]) &&
  isset($_FILES["attachment"])
) {  
  
  $email = trim($_POST["email"]);
  $subject = trim($_POST["subject"]);
  $message = trim($_POST["message"]);
  $file = $_FILES["attachment"];

  // Email Validation
  if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $error = "Invalid Email address";
  }
  // If there is no attachment to send then set the $file = false;
  if ($file["error"] === 4) {
    $file = false;
  }
 
  // Chekcing File size max 25MB
  if ($file && ($file["error"] === 1 || $file["size"] > 1048576 * 25)) {
    $error = "File is too large Max 25MB";
  }

  // If there is no error then cll the sen_mail() function
  if ($error === false) {

    $form_data = [
      "email" => $email,
      "subject" => $subject,
      "message" => $message,
      "atch" => $file
    ];

    $result = send_mail($form_data);

    if ($result) {
      $success = "Email has been sent.";
    } else {
      $error = "Email could not be delivered";
    }
  }
}
?>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>PHPMailer Send Emails</title>
  <link href="./style.css" rel="stylesheet">
</head>

<body>

  <div class="container">
    <h1>PHPMailer Send Emails</h1>
    <form action="" method="POST" enctype="multipart/form-data">
      <label for="email">To:</label>
      <input type="email" name="email" id="email" autocomplete="off" placeholder="Email address" />
      <label for="subject">Subject:</label>
      <input type="text" name="subject" id="subject" autocomplete="off" placeholder="Subject">
      <label for="message">Message:</label>
      <textarea name="message" id="message" placeholder="Message"></textarea>
      <label for="attachment">Attachment: (Max 25MB)</label>
      <input type="file" name="attachment" id="attachment">
      <?php echo ($success) ? '<div class="message">' . $success . '</div>' : ''; ?>
      <?php echo ($error) ? '<div class="message error">' . $error . '</div>' : ''; ?>
      <button type="submit">Send</button>
    </form>
  </div>
  <script>
    // this js code stops the multiple form submission on page refresh
    if (window.history.replaceState) {
      window.history.replaceState(null, null, window.location.href);
    }
  </script>
</body>
</html>

style.css contains the stylesheet for the HTML Form

@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap');
*{
  box-sizing: border-box;
}
:root{
  --main-color:#7A3653;

}
html{
  font-size: 16px;
}
body{
  font-family: 'Open Sans', sans-serif;
  background:#f7f7f7;
}
h1{
  text-align: center;
  margin-bottom: 0;
}
form{
  display: flex;
  flex-direction: column;
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
}

button,input,textarea{
  font-family: 'Open Sans', sans-serif;
  font-size: 1rem;
  padding: 10px;
}

button[type="submit"],
input,textarea{
  border: 1px solid rgba(0, 0, 0, .3);
  border-radius: 3px;
  outline: none;
}
textarea{
  resize: vertical;
  min-height: 120px;
}

input:is(:hover,:focus),
textarea:is(:hover,:focus){
  border-color: var(--main-color);
}

button[type="submit"]{
  background: var(--main-color);
  color: white;
  cursor: pointer;
  font-weight: 700;
  margin-top: 15px;
}

button[type="submit"]:hover{
  outline:var(--main-color) solid 2px;
  outline-offset: 2px;
}

label{
  font-weight: 700;
  margin: 10px 0 3px 0;
}

.message{
  border: 2px solid #4BB543;
  border-radius: 3px;
  background: hsl(116, 46%, 90%);
  margin-top: 15px;
  padding: 10px;
}
.error{
  border-color: #ff3333;
  background: hsl(0, 100%, 90%);
}