6-4:メールマガジン送信機能を追加する

2019/05/31

概要

「DM受信する」を選択した会員に管理画面からメールマガジンを送信する機能を実装していきます。
メールを作成し、送信ボタンを押すと、DM希望者を抽出してループで送信する機能です。
※実際にサービスで実装する場合、利用者が何千・何万人となるとこの実装方法では送信に何日もかかってしまうので、メール送信サービスと連携して送信機能を実装しますが、本章では連携はせず実装していきます。

フォルダ階層

完成イメージ

会員一覧

DM作成フォーム

送信完了

全体の手順

手順は以下の通りです。

  1. メールフォームの作成
  2. 送信機能の実装
  3. メールの確認

メールフォームの作成

メルマガ配信ボタンの追加

admin/users.phpにメルマガ配信ボタンを追加します。
create_dm.phpというファイルでメール作成フォームを作成するので、リンク先はcreate_dm.phpを指定します。
CSV出力ボタンの隣に実装しました。
admin/users.php

+   <button type="button" class="btn btn-blue" onclick="location.href='./create_dm.php'">メルマガ配信</button>
    <buttontype="button" class="btn btn-gray" onclick="location.href='download.php'">CSV出力</button>

メールフォームの作成

adminフォルダにcreate_dm.phpというファイルを作成します。
PHPでログインチェックをして、HTMLでフォームを作成しています。
フォームは、タイトルと本文のみです。
フォームのmethodはPOSTを指定、送り先は送信を実装するsend_dm.phpとしました。
create_dm.php

<?php
    session_start();

    if($_SESSION['admin_login'] == false){
        header("Location:./index.html");
        exit;
    }

?>
<!DOCTYPE html>
<html>

<head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-13xxxxxxxxx"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'UA-13xxxxxxxxx');
    </script>

    <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>メルマガ作成</title>

    <link rel="icon" href="favicon.ico">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
        integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">

    <!-- css -->
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <header>
        <div class="container">
            <div class="header-logo">
                <h1><a href="dashboard.php">管理画面</a></h1>
            </div>

            <nav class="menu-right menu">
                <a href="logout.php">ログアウト</a>
            </nav>
        </div>
    </header>
    <main>
        <div class="wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>メルマガ作成</h3>
                </div>
                <form class="edit-form" method="POST" action="send_dm.php">
                    <div class="form-group">
                        <p>タイトル</p>
                        <input type="text" name="title" required>
                    </div>
                    <div class="form-group">
                        <p>本文</p>
                        <textarea name="content"></textarea>
                    </div>
                    <button type="submit" class="btn btn-blue">送信する</button>
                </form>
            </div>
        </div>
    </main>
    <footer>
        <div class="container">
            <p>Copyright @ 2018 SQUARE, inc</p>
        </div>
    </footer>
</body>

</html>

このようなフォームができます。

送信機能実装

送信を実行するファイルsend_dm.phpをadminフォルダに作成していきます。

ログインチェック

ログインチェックをします。
admin/send_dm.php

<?php
    //sessionでログイン制限
    session_start();

    if($_SESSION['admin_login'] == false){
        header("Location:./index.html");
        exit;
    }

PHPMailerの設定

お問い合わせフォームで利用したPHPMailerを使います。
PHPMailerソースを読み込み、使える状態にします。
PHPMailerは、adminフォルダと同じ階層にあるので、指定するpathに気をつけます。
admin/send_dm.php

    <?php
        //sessionでログイン制限
        session_start();

        if($_SESSION['admin_login'] == false){
            header("Location:./index.html");
            exit;
        }

+       //PHPMailerソースを読み込む
+       require '../PHPMailer/src/PHPMailer.php';
+       require '../PHPMailer/src/SMTP.php';
+       require '../PHPMailer/src/POP3.php';
+       require '../PHPMailer/src/Exception.php';
+       require '../PHPMailer/src/OAuth.php';
+       require '../PHPMailer/language/phpmailer.lang-ja.php';
+       
+       //使う
+       use PHPMailer\PHPMailer\PHPMailer;
+       use PHPMailer\PHPMailer\Exception;

データの値の受け取り

POSTで送られてきたデータを受け取ります。
本文は改行コードも注意します。
admin/send_dm.php

   //PHPMailerソースを読み込む
   require '../PHPMailer/src/PHPMailer.php';
   require '../PHPMailer/src/SMTP.php';
   require '../PHPMailer/src/POP3.php';
   require '../PHPMailer/src/Exception.php';
   require '../PHPMailer/src/OAuth.php';
   require '../PHPMailer/language/phpmailer.lang-ja.php';

   //使う
   use PHPMailer\PHPMailer\PHPMailer;
   use PHPMailer\PHPMailer\Exception;

+  $title = isset($_POST['title'])? htmlspecialchars($_POST['title']):'';
+  $content = isset($_POST['content'])? htmlspecialchars($_POST['content']):'';
+  $content = nl2br($content);

メール送信の設定

次に、PHPMailerオブジェクトを作成します。
SMTPDebugを2にすると、開発中のエラーなど表示されて便利です。
実装が完了したら0にしますが、開発中は2としておきます。
mailtrapでテスト送信したいのでメールホストはsmtp.mailtrap.ioを指定し、UsernameとPasswordは最初のmailtrapで取得したuser_name、passwordを記述します。
admin/send_dm.php

   $title = isset($_POST['title'])? htmlspecialchars($_POST['title']):'';
   $content = isset($_POST['content'])? htmlspecialchars($_POST['content']):'';
   $content = nl2br($content);

+  //送信設定
+  $mail = new PHPMailer(true);
+  $mail->SMTPDebug = 2; //デバックモード 0にすると表示されない 
+  $mail->isSMTP();
+  $mail->Host='smtp.mailtrap.io';
+  $mail->SMTPAuth= true;
+  $mail->Username = 'xxxxxxxxx';
+  $mail->Password = 'xxxxxxxx';
+  $mail->SMTPSecure = 'tls';
+  $mail->Port = 2525;
+  $mail->Charset = 'utf-8';
+  $mail->isHTML(true);
+  $mail->CharSet = 'UTF-8'; //文字化け防止

DM希望者の抽出

DBに接続してSELECT文でDM希望者を抽出します。
「DM受信する」の人は、dmカラムに「1」が入っている人なので、whereでdm=1を指定しています。
admin/send_dm.php

   //送信設定
   $mail = new PHPMailer(true);
   $mail->SMTPDebug = 2; //デバックモード 0にすると表示されない 
   $mail->isSMTP();
   $mail->Host='smtp.mailtrap.io';
   $mail->SMTPAuth= true;
   $mail->Username = 'xxxxxxxxx';
   $mail->Password = 'xxxxxxxxxx';
   $mail->SMTPSecure = 'tls';
   $mail->Port = 2525;
   $mail->Charset = 'utf-8';
   $mail->isHTML(true);
   $mail->CharSet = 'UTF-8'; //文字化け防止

+   //DB接続
+   try{
+       $dbh = new PDO("mysql:host=localhost;dbname=corporate_db","root","root");
+   }catch(PDOException $e){
+       var_dump($e->getMessage());
+       exit;
+   }
+   
+   $stmt = $dbh->prepare("SELECT * FROM users WHERE dm=1");
+   $stmt->execute();
+   $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

送信実行

リストを抽出できたら、ループで送信を実行していきます。
$usersで取得したemailを送信先、nameを送信宛名と本文の最初に使います。
try-catchで囲んでエラーを検出できるようにしました。
送信完了画面に表示するメッセージ用に$resultパラメータを設定します。
admin/send_dm.php

    $stmt = $dbh->prepare("SELECT * FROM users WHERE dm=1");
    $stmt->execute();
    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

+   try{
+       foreach($users as $user){
+           $mail->setFrom('<送信者のメールアドレス>','test');
+           $mail->addAddress($user['email'],$user['name']);
+           $mail->Subject = mb_encode_mimeheader($title,'ISO-2022-JP');
+           $mail->Body = $user['name']."さま<br>".$content;
+           $mail->send();
+       }
+       $result = 'メルマガ送信完了しました。';
+   }catch(Exception $e){
+       $result = '送信できませんでした。';
+   }

送信確認

この状態で、create_dm.phpからタイトルと本文を指定して送信チェックします。
send_dm.phpは送信経過が表示されます。
一番最後まで見ると、Ok:queuedと表示されているので実行が完了したことがわかります。

※2019年5月29日時点では、mailtrapの仕様による制限でメール送信が2件までしか正常に実行されないようです(通常のメールホストの場合は問題ありません)。テストの際はdmの配信人数に注意してください。
mailtrapの受信ボックスに、DM希望者に対応したメールが届いていれば送信はOKです。

送信結果を表示

phpMailerのデバッグモードを0にして、HTMLで送信完了画面を表示します。
admin/send_dm.php

   //送信設定
   $mail = new PHPMailer(true);
+  $mail->SMTPDebug = 0; //デバックモード 0にすると表示されない 
-  $mail->SMTPDebug = 2; //デバックモード 0にすると表示されない 
   $mail->isSMTP();
   $mail->Host='smtp.mailtrap.io';
   $mail->SMTPAuth= true;
   $mail->Username = 'xxxxxxxxxx';
   $mail->Password = 'xxxxxxx';
   $mail->SMTPSecure = 'tls';
   $mail->Port = 2525;
   $mail->Charset = 'utf-8';
   $mail->isHTML(true);
   $mail->CharSet = 'UTF-8'; //文字化け防止

phpの下にhtmlで記述します。
$resultがh3タグで表示されるようにしています。
admin/send_dm.php

?>
<!DOCTYPE html>
<html>

<head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-13xxxxxxxxx"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'UA-13xxxxxxxxx');
    </script>

    <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>メルマガ配信</title>

    <link rel="icon" href="favicon.ico">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
        integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">

    <!-- css -->
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <header>
        <div class="container">
            <div class="header-logo">
                <h1><a href="dashboard.html">管理画面</a></h1>
            </div>

            <nav class="menu-right menu">
                <a href="logout.php">ログアウト</a>
            </nav>
        </div>
    </header>
    <main>
        <div class="wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3><?php echo $result; ?></h3>
                </div>
            </div>
        </div>
    </main>
    <footer>
        <div class="container">
            <p>Copyright @ 2018 SQUARE, inc</p>
        </div>
    </footer>
</body>

</html>

メール確認

create_dm.phpから実行してみます。

管理画面ではメルマガ送信完了が表示され、mailtrapにDM希望者に対応したメールが届いていれば実装完了です。

コード

https://github.com/bluecode-io/web-basic/tree/basic6-4