PHP 技術記事

PHP MailerでGmail + XOAuth2 を使ってメール送信の実装をする

本サイトの記事内にアフィリエイト広告が含まれる場合があります。

PHP Mailerを使ってGmail(XOAUTH2)を使ったメール送信の実装のサムネイル画像

Yuki

inote, Inc. CEO 文系芸術系大学出身。学生時代はフリーランスでWEB制作・開発しながら、2社で長期エンジニアインターンを経験しました(2年半)。 23卒で、自社開発ベンチャー企業に入社しエンジニアやPMとしてサービスに関わり、2024年1月起業。自社サービスや受託開発で年収1億円を目指して奮闘中。 お仕事依頼はお問い合わせフォームからお問い合わせお願いします。

MAMPとPHP Mailerでメールの送信の実装をしました。

少し時間がかかったので、ブログに書いていきたいと思います。

Gmailでは、SMTP認証にXOAUTH2を使用することが推奨されるようになりました。

以前までは、Googleアカウントの設定で安全性の低いアプリの許可をオンにしたら動くということがあったかもしれないですが、2022 年 5 月 30 日より、Google は、ユーザー名とパスワードのみで Google アカウントにログインするサードパーティ製のアプリとデバイスについてサポートを終了を公表しています。

なので、今回はXOAUTH2を使ったメール送信を行う方法を解説します。

コードのみをみたい場合は全体コードを参照ください。

MAMP環境構築

この記事ではMAMPの環境構築は省略させていただきます🙇‍♂️

下記リンクが公式サイトなので、ご自身のPCへダウンロードしてください。

https://www.mamp.info/en/windows/

Gmailの設定

Gmailの設定からメール転送とPOP/IMAPのところへいってIMAPを有効にするに変更して変更を保存します。

Google Cloud Platformの設定

OAuth接続に必要な情報を取得していきます。必要になってくるのは、

  • クライアント ID
  • クライアントシークレット
  • リフレッシュトークン

です。

https://console.cloud.google.com/getting-started?hl=ja (Google Cloud Platform)にアクセスします。

初めてアクセスした方は下記の画像のようなモーダルウインドウが出るので、①にチェックを入れて「同意して続行」をクリックします。

プロジェクトの作成

ヘッダーのプロジェクトの選択をクリックします。

すると次は下記のようなモーダルウインドウが出るので、右上の新しいプロジェクトをクリックしてください。

新しいプロジェクト作成画面で、プロジェクト名(任意)を記入して作成ボタンを押します。

そしてもう一度ヘッダーの「プロジェクトの選択」をクリックしてください。

すると、最近のプロジェクトという欄に先ほど作ったプロジェクト名が出てくるので、クリックして右下の開くを押します。

OAuth同意画面の作成

次に左側のグローバルメニューから、APIとサービスをホバーしてOAuth同意画面をクリックします。

次の画面で、User Typeを外部にセレクトして、作成をクリックします。

アプリ情報を記入していきます。ここではアプリ名とユーザサポートメールを入力します。

一番下にあるデベロッパーの連絡先にはお好きなメールアドレスを入力してください。

入力が完了したら「保存して次へ」を押します。

スコープとテストユーザーについても、入力なしで保存して次へを押して言ってください。

概要の画面にまでいったら作成完了なので、ダッシュボードに戻るをクリックしましょう。

ダッシュボードのアプリを公開をクリックしてアプリを公開にします。(テスト状態だとリフレッシュトークンが取得できませんでした)

認証情報(OAuthクライアントID)の作成

次に①認証情報をクリック、②認証情報を作成をクリックします。

次にOAuthクライアントIDをクリック

アプリケーションの種類はウェブアプリケーションを選択。

承認済みリダイレクトURIにはhttps://developers.google.com/oauthplaygroundを入力してください。

ここまでできたら作成ボタンを押します。

するとOAuthクライアントを作成しましたと表示が出るので、クライアントIDとクライアントシークレットをコピーしてどこかに保存しておいてください。

リフレッシュトークンの取得

https://developers.google.com/oauthplayground/ にアクセスします。

右上の歯車マークをクリックして、Use your own OAuth credentialsにチェックを入れると、OAuth Client ID とOAuth Client secretの入力欄が出るので、先ほどコピーしたものをペーストします。

次に左側のinput your own scopesの部分にhttps://mail.google.com/を入力して、Authorize APIsをクリックします。

するとこのような画面になるので、アカウント名をクリックしてログインします。

このアプリはGoogleで確認されていませんの画面にいった方は詳細をクリックして安全でないページに移動を押して次に進みます。

続行をクリックします。

先ほどの画面に戻るので、Exchange authorization code for tokensをクリックします。

リフレッシュトークンが発行されました。

この値を使って、お問い合わせフォームを実装していきます。

お問い合わせフォームとサンクスページHTMLの作成

今回は、PHP Mailerでのメールの送信の解説中心にしたいので、フォームとお問い合わせ送信後のサンクスページのHTMLとCSSのコードを載せるだけで、この項目は終わりにしたいと思います。

スタイルはBootstrapのCDNを読み込んで使っています😇

<!DOCTYPE html>
<html lang="ja">

<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>Contact form</title>
  <!-- CSS only -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>
  <div class="container-md p-5">
    <h2 class="mb-3">お問い合わせ</h2>

    <form action="<?php echo get_self_url(); ?>" method="POST">
      <div class="mb-3">
        <label for="name" class="form-label">お名前</label>
        <input type="text" class="form-control" id="name" name="name">
      </div>
      <div class="mb-3">
        <label for="mail" class="form-label">メールアドレス</label>
        <input type="email" class="form-control" id="mail" name="mail">
      </div>
      <div class="mb-3">
        <label for="content" class="form-label">お問い合わせ内容</label>
        <textarea class="form-control" name="content" rows="5" ></textarea>
      </div>
      <button type="submit" class="btn btn-primary">送信</button>
    </form>
  </div>


</body>

</html>
<!DOCTYPE html>
<html lang="ja">

<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>Contact form</title>
  <!-- CSS only -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>
  <div class="container-md p-5">
    <h2 class="mb-3">お問い合わせありがとうございました。</h2>
    <a href="contact-form.php">
      トップに戻る
    </a>
  </div>
</body>

</html>

Composerでライブラリのインストール

composerのインストール手順は今回は割愛させていただきます。

composer require phpmailer/phpmailer
composer require league/oauth2-google

Composerのエラー

Fatal error: Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.1.0". You are running 8.0.8.

コードを書いていて、上記のエラーが出た場合は下記をターミナルでうってください。

composer install --ignore-platform-reqs

PHP実装

今回はGithubのコードを参考に実装しました。↓

https://github.com/PHPMailer/PHPMailer/blob/master/examples/gmail_xoauth.phps

libディレクトリを作成し、その中にconfig.phpとfunctions.phpのファイルを作成します。

config.phpに定数としてメールアドレス、クライアント ID、クライアントシークレット、リフレッシュトークン等をまとめます。

使用する際は{{}}の部分をご自身のものに置き換えてください。

<?php
define("EMAIL", "{{EMAIL}}");
define("CLIENT_ID", "{{CLIENT_ID}}");
define("CLIENT_SECRET", "{{CLIENT_SECRET}}");
define("REFRESH_TOKEN", "{{REFRESH_TOKEN}}");

次にfunctions.phpに関数で処理をまとめていきます。

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

date_default_timezone_set('Etc/UTC');
require dirname(__FILE__) . '/../vendor/autoload.php';
require 'config.php';

function get_self_url() {
  $self_url = $_SERVER['PHP_SELF'];
  return $self_url;
}

function check_form_validation($form_data) {
  if (!$form_data['name'] || !$form_data['mail'] || !$form_data['content']) {
    return false;
  } else {
    return true;
  }
}

function send_email($data) {
  $mail = new PHPMailer();
  $mail->isSMTP();
  $mail->SMTPDebug = SMTP::DEBUG_SERVER;
  $mail->Host = 'smtp.gmail.com';
  $mail->Port = 465;
  $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
  $mail->SMTPAuth = true;
  $mail->AuthType = 'XOAUTH2';

  $provider = new Google(
    [
      'clientId' => CLIENT_ID,
      'clientSecret' => CLIENT_SECRET,
    ]
  );

  $mail->setOAuth(
    new OAuth(
      [
        'provider' => $provider,
        'clientId' => CLIENT_ID,
        'clientSecret' => CLIENT_SECRET,
        'refreshToken' => REFRESH_TOKEN,
        'userName' => EMAIL,
      ]
    )
  );

  $mail->setFrom(EMAIL, 'site title');
  $mail->addAddress($data["mail"], $data["name"]);
  $mailBody = "
    お名前: {$data['name']}
    メールアドレス: {$data['mail']}
    お問い合わせ内容: {$data['content']}
  ";
  $mail->Subject = 'お問い合わせありがとうございます。';

  $mail->CharSet = PHPMailer::CHARSET_UTF8;
  $mail->Body = $mailBody;

  if (!$mail->send()) {
    echo 'Mailer Error: ' . $mail->ErrorInfo;
  } else {
    header("Location: ./thanks.php");
    exit;
  }
}

軽くコードの解説していきます。

10行目のrequireで先ほど作成したconfig.phpを読み込んでいます。

require 'config.php';

12行目のget_self_url関数は現在のファイルパスを返す関数です。

function get_self_url() {
  $self_url = $_SERVER['PHP_SELF'];
  return $self_url;
}

17行目はのcheck_form_validation関数はフォームの入力の値が空だった場合、falseを返し、空欄がない場合はtrueを返す関数です。こちらについては、フォームの値それぞれ厳密にバリデーションをかけてれてないので、追記する必要があると思います。

function check_form_validation($form_data) {
  if (!$form_data['name'] || !$form_data['mail'] || !$form_data['content']) {
    return false;
  } else {
    return true;
  }
}

今回はメールを送ることを目的としているので、バリデーションの解説はここまでにします。

25行目以降のsend_email関数はPHP Mailerでメールを送る関数です。

function send_email($data) {
  $mail = new PHPMailer();
  $mail->isSMTP();
  $mail->SMTPDebug = SMTP::DEBUG_SERVER;
  $mail->Host = 'smtp.gmail.com';
  $mail->Port = 465;
  $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
  $mail->SMTPAuth = true;
  $mail->AuthType = 'XOAUTH2';

  $provider = new Google(
    [
      'clientId' => CLIENT_ID,
      'clientSecret' => CLIENT_SECRET,
    ]
  );

  $mail->setOAuth(
    new OAuth(
      [
        'provider' => $provider,
        'clientId' => CLIENT_ID,
        'clientSecret' => CLIENT_SECRET,
        'refreshToken' => REFRESH_TOKEN,
        'userName' => EMAIL,
      ]
    )
  );

  $mail->setFrom(EMAIL, 'site title');
  $mail->addAddress($data["mail"], $data["name"]);
  $mailBody = "
    お名前: {$data['name']}
    メールアドレス: {$data['mail']}
    お問い合わせ内容: {$data['content']}
  ";
  $mail->Subject = 'お問い合わせありがとうございます。';

  $mail->CharSet = PHPMailer::CHARSET_UTF8;
  $mail->Body = $mailBody;

  if (!$mail->send()) {
    echo 'Mailer Error: ' . $mail->ErrorInfo;
  } else {
    header("Location: ./thanks.php");
    exit;
  }
}

$mail->setFromでメールの送信元

$mail->addAddressで送信先の指定

$mail->Subjectで件名

$mail->Bodyでメールの本文を設定します。

  $mail->setFrom(EMAIL, 'site title');
  $mail->addAddress($data["mail"], $data["name"]);
  $mailBody = "
    お名前: {$data['name']}
    メールアドレス: {$data['mail']}
    お問い合わせ内容: {$data['content']}
  ";
  $mail->Subject = 'お問い合わせありがとうございます。';
  $mail->Body = $mailBody;

最後にメール送信が完了したらthanks.phpにリダイレクト、できなかった場合はエラー表示されるように書いてます。

if (!$mail->send()) {
    echo 'Mailer Error: ' . $mail->ErrorInfo;
  } else {
    header("Location: ./thanks.php");
    exit;
  }

フォームの送信時に関数の実行

フォームの書いてあるコードの上部に以下コードを追加します。

<?php
require 'lib/functions.php';
$error = false;

if (!empty($_POST)) {
  if (!check_form_validation($_POST)) {
    $error = true;
  } else {
    send_email($_POST);
  }
}
?>

POSTメソッドが実行されるときに、functions.phpで書いたコードを実行するようになっています。

全体コード

<?php
require 'lib/functions.php';
$error = false;

if (!empty($_POST)) {
  if (!check_form_validation($_POST)) {
    $error = true;
  } else {
    send_email($_POST);
  }
}

?>

<!DOCTYPE html>
<html lang="ja">

<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>Contact form</title>
  <!-- CSS only -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>
  <div class="container-md p-5">
    <h2 class="mb-3">お問い合わせ</h2>

    <form action="<?php echo get_self_url(); ?>" method="POST">
      <div class="mb-3">
        <label for="name" class="form-label">お名前</label>
        <input type="text" class="form-control" id="name" name="name">
      </div>
      <div class="mb-3">
        <label for="mail" class="form-label">メールアドレス</label>
        <input type="email" class="form-control" id="mail" name="mail">
      </div>
      <div class="mb-3">
        <label for="content" class="form-label">お問い合わせ内容</label>
        <textarea class="form-control" name="content" rows="5"></textarea>
      </div>
      <button type="submit" class="btn btn-primary">送信</button>

      <?php if ($error) : ?>
        <div class="alert alert-danger mt-5" role="alert">
          入力内容に不備があります。
        </div>
      <?php endif; ?>

    </form>
  </div>


</body>

</html>
<?php
define("EMAIL", "{{EMAIL}}");
define("CLIENT_ID", "{{CLIENT_ID}}");
define("CLIENT_SECRET", "{{CLIENT_SECRET}}");
define("REFRESH_TOKEN", "{{REFRESH_TOKEN}}");
<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

date_default_timezone_set('Etc/UTC');
require dirname(__FILE__) . '/../vendor/autoload.php';
require 'config.php';

function get_self_url() {
  $self_url = $_SERVER['PHP_SELF'];
  return $self_url;
}

function check_form_validation($form_data) {
  if (!$form_data['name'] || !$form_data['mail'] || !$form_data['content']) {
    return false;
  } else {
    return true;
  }
}

function send_email($data) {
  $mail = new PHPMailer();
  $mail->isSMTP();
  $mail->SMTPDebug = SMTP::DEBUG_SERVER;
  $mail->Host = 'smtp.gmail.com';
  $mail->Port = 465;
  $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
  $mail->SMTPAuth = true;
  $mail->AuthType = 'XOAUTH2';

  $provider = new Google(
    [
      'clientId' => CLIENT_ID,
      'clientSecret' => CLIENT_SECRET,
    ]
  );

  $mail->setOAuth(
    new OAuth(
      [
        'provider' => $provider,
        'clientId' => CLIENT_ID,
        'clientSecret' => CLIENT_SECRET,
        'refreshToken' => REFRESH_TOKEN,
        'userName' => EMAIL,
      ]
    )
  );

  $mail->setFrom(EMAIL, 'site title');
  $mail->addAddress($data["mail"], $data["name"]);
  $mailBody = "
    お名前: {$data['name']}
    メールアドレス: {$data['mail']}
    お問い合わせ内容: {$data['content']}
  ";
  $mail->Subject = 'お問い合わせありがとうございます。';

  $mail->CharSet = PHPMailer::CHARSET_UTF8;
  $mail->Body = $mailBody;

  if (!$mail->send()) {
    echo 'Mailer Error: ' . $mail->ErrorInfo;
  } else {
    header("Location: ./thanks.php");
    exit;
  }
}

完成イメージ

お問い合わせフォームに入力して送信を押すと、

お問い合わせフォーム

サンクスページが表示されます。

お問い合わせ完了後遷移先ページ
メール画像

上記のように入力された内容がメールに届けば完了です。

お疲れ様でした。

参考

PHP Mailer Github https://github.com/PHPMailer/PHPMailer

Bootstrap https://getbootstrap.jp/docs/5.0/layout/containers/

  • この記事を書いた人

Yuki

inote, Inc. CEO 文系芸術系大学出身。学生時代はフリーランスでWEB制作・開発しながら、2社で長期エンジニアインターンを経験しました(2年半)。 23卒で、自社開発ベンチャー企業に入社しエンジニアやPMとしてサービスに関わり、2024年1月起業。自社サービスや受託開発で年収1億円を目指して奮闘中。 お仕事依頼はお問い合わせフォームからお問い合わせお願いします。

-PHP, 技術記事
-