Mengirim email menggunakan PhpMailer dengan Gmail XOAUTH2

oleh Vincy. Terakhir diubah pada 29 Mei 2021.

Apakah Anda menyimpan kata sandi email Anda dalam file PHP sebagai teks biasa? Jika server Anda disusupi, apa yang akan terjadi pada email Anda? Artikel ini untuk Anda.

Ketika orang berkonsultasi tentang komponen pengiriman email, fokus pertama saya adalah pada keamanan. Tentu saja, ini adalah contoh klasik di mana pengembang aplikasi harus menjaga keamanan.

Meskipun PHP memiliki built-in mail function mail(), saya telah mencari cara yang lebih baik untuk melakukan ini. Ini tentang menjamin keamanan yang dapat diandalkan saat mengonfigurasi layanan pengiriman email dari suatu aplikasi.

Pustaka PHPMailer adalah komponen pengiriman email yang tidak ada duanya dengan fitur-fitur canggih. Saya menggunakan klien Google OAuth untuk mengirim email melalui PHPMailer dengan cara yang aman.

Saya telah membuat contoh sederhana dan mendasar untuk membuat skrip pengiriman email. Mari kita masuk untuk mempelajari lebih lanjut tentang mengirim email dengan PHPMailer melalui Gmail XOAUTH2.

Apa yang ada di dalam?

  1. Tentang contoh ini
  2. Ketergantungan dan perintah instalasi
  3. Hasilkan kunci API dan segarkan token
  4. Template UI dan validasi sisi klien
  5. Pengontrol PHP memanggil skrip pengiriman surat
  6. Arahan yang dapat dikonfigurasi aplikasi
  7. Layanan email menggunakan PhpMailer dan Gmail XOAUTH2

Tentang contoh ini

Contoh ini untuk membuat layanan surat untuk mengirim email menggunakan PHPMailer melalui Gmail XOAUTH2.

Ini menunjukkan formulir kontak kepada pengguna untuk memasukkan detailnya. Tindakan pengiriman formulir mengirimkan email kontak ke penerima. Jika Anda menginginkan komponen formulir kontak yang aman, dapatkan Iris.

Dependensi yang diperlukan diinstal melalui komposer dan diintegrasikan ke dalam contoh ini untuk mengirim email.

Konfigurasi aplikasi mengatur kunci untuk meminta otentikasi berbasis token saat mengirim email.

Ini tidak hanya mencakup pengiriman surat tetapi juga komponen formulir kontak kerja ujung ke ujung.

Gambar berikut menunjukkan struktur file dari contoh ini. Direktori vendor diperluas untuk menampilkan dependensi yang diperlukan untuk kode ini.

Formulir Kontak File Email OAuth

Ketergantungan dan perintah instalasi

Seperti yang kami sebutkan di bagian pendahuluan, kode ini menggunakan PHPMailer dan pustaka klien OAuth.

Pustaka dependen yang diperlukan diunduh secara otomatis dengan menginstal dua halaman ini melalui alat manajemen paket seperti: komposer.

Perintah untuk menginstal PHPMailer melalui composer adalah,

composer require phpmailer/phpmailer

Untuk menggunakan Google OAuth, jalankan perintah ini untuk mengunduh dependensi yang ditunjukkan pada gambar struktur file.

composer require league/oauth2-google

Hasilkan kunci API dan segarkan token

Berikut adalah langkah-langkah untuk membuat proyek Google API dan mendapatkan kunci dan token. Kunci-kunci ini adalah parameter untuk proses otentikasi berbasis token.

  1. Masuk ke akun Google dan buka konsol platform cloud.
  2. Dari menu geser kiri, navigasikan IAM & Admin -> Kelola Sumber Daya. Klik BUAT PROYEK dan masukkan detailnya.
  3. Pergi ke API & Layanan -> Perpustakaan dan aktifkan API Gmail.
  4. Pergi ke API & Layanan -> Kredensial dan klik BUAT KREDENSIAL -> ID klien OAuth.
  5. Pilih jenis aplikasi dan isi detail lainnya untuk menghasilkan kunci.

Hasilkan Kunci dan Token API Gmail

Setelah mendapatkan kunci, konfigurasikan ke file berikut yang disertakan dengan PHPMailer paket. Ini untuk mendapatkan token penyegaran.

vendor/phpmailer/phpmailer/get_oauth_token.php

Kode berikut menunjukkan tempat untuk mengatur kunci klien-id dan rahasia klien untuk mendapatkan token penyegaran.


<?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 PHPMailerPHPMailer;

/**
 * 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 LeagueOAuth2ClientProviderGoogle;
//@see https://packagist.org/packages/hayageek/oauth2-yahoo
use HayageekOAuth2ClientProviderYahoo;
//@see https://github.com/stevenmaguire/oauth2-microsoft
use StevenmaguireOAuth2ClientProviderMicrosoft;

if (!isset($_GET['code']) && !isset($_GET['provider'])) {
    ?>
<html>
<body>Select Provider:<br>
<a href="https://phppot.com/php/sending-email-using-phpmailer-with-gmail-xoauth2/?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();
}

Template UI dan validasi sisi klien

Ini adalah kode HTML untuk Templat formulir kontak sederhana. Ini memicu validasi formulir dan skrip pengiriman email back-end saat mengirimkan formulir.

Ini cukup jelas dengan bidang formulir biasa dan atribut semantik.

index.php

<html>
<head>
<title>Contact Us Form</title>
<link rel="stylesheet" type="text/css" href="https://phppot.com/php/sending-email-using-phpmailer-with-gmail-xoauth2/assets/css/style.css" />
</head>
<body>
    <div class="form-container">
        <form name="frmContact" id="" frmContact"" method="post"
            action="" enctype="multipart/form-data"
            onsubmit="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>

Fungsi validasi formulir membatasi pengiriman formulir hingga mendapatkan nilai yang tidak kosong dari semua bidang.

Ini memvalidasi data bidang email jika cocok dengan pola regex yang ditentukan.

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;
}

Pengontrol PHP memanggil skrip pengiriman surat

Script ini ditambahkan di awal file index.php di atas form kontak HTML.

Ini menghubungkan PHP MailService untuk mengirim email kontak menggunakan PHPMailer dengan XOAUTH2.

Ini menangkap respon dari proses pengiriman surat. Ini mengakui pengguna akhir untuk mengetahui apakah pesan kontak diterima atau tidak.

Untuk mengirim email dengan PHPMailer menggunakan SMTP GMail, artikel tertaut memiliki unduhan dengan kode yang sesuai.

index.php (kode PHP untuk memanggil layanan email untuk mengirim email)

<?php
namespace Phppot;

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

Arahan yang dapat dikonfigurasi aplikasi

Ini adalah file konfigurasi yang dibuat untuk kode contoh ini. Ini mendefinisikan konstanta PHP untuk menahan kunci dan token yang dihasilkan sebelumnya untuk otentikasi.

Ini juga menentukan alamat email penerima dan email serta detail pengguna OAuth.

lib/Config.php

<?php
/**
 * Copyright (C) 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;
}

Layanan email menggunakan PhpMailer dan Gmail XOAUTH2

Fungsi sendContactMail() menyetel detail formulir kontak untuk membuat konten isi email.

Ini membuat instance PHPMailer dan menetapkan atribut untuk mengotentikasi permintaan pengiriman email.

Ini menetapkan instance penyedia OAuth Google dengan kunci dan token yang dihasilkan serta detail pengguna OAuth.

Kemudian, ia menambahkan atribut email rutin, email target, email-dari, balasan-ke, dan lainnya.

Ini membangun respons JSON untuk mengembalikan hasil dari proses pengiriman email.

lib/MailService.php

<?php
namespace Phppot;

use PhppotConfig;
use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;

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;
    }
}

formulir kontak
Sumber yang dapat diunduh ini tidak dengan paket-paket dependen. Gunakan komposer untuk mengunduh dependensi.
Unduh

Kembali ke Atas

[ad_2]
Source link