Twilio SendGridを使ってLaravelでWebベースのメール送信機能を構築する方法

LaravelでWebベースのメール送信機能を構築する方法

この記事は How to Build a Web-Based Email Client in Laravel PHP using Twilio SendGrid の抄訳です。

新しいアプリケーションを構築し一般に公開する際は、非常に神経を使うものです。特に、開発やマーケティングの初期段階では、ユーザと継続的に連絡を取り合うことが大切です。

このコミュニケーションの手段としてメールは欠かせません。メールは、新機能や不具合の修正をユーザへ知らせたり、非アクティブなユーザをフォローアップしたりするのに最適です。

そこで、このチュートリアルでは、既存のLaravelアプリケーションにWebベースのメール送信機能を追加する方法を見ていきます。このチュートリアルを終了すると、LaravelとTwilio SendGridを利用したメールシステムを構築できるようになります。

必要なもの

このチュートリアルで必要なものは以下のとおりです。

・基本的なLaravelの知識
Laravelのインストール
Composerのグローバルインストール
MySQLのセットアップ
SendGridのアカウント

はじめに

はじめに、今回のアプリケーション用の新しいLaravelプロジェクトを作成します。このとき、Laravel InstallerとComposerのどちらを利用しても構いませんが、本チュートリアルでは前者を使います。もしLaravel Installerをインストールしていなければ、ドキュメントで手順を確認してください。インストールできたら、ターミナルで以下のコマンドを実行します。

$ laravel new custom-mail-system

ここで、SendGridへのアクセスにはSendGrid PHPライブラリを利用します。プロジェクトディレクトリで以下のコマンドを実行し、Composer経由でライブラリをインストールします。

$ composer require "sendgrid/sendgrid"

SendGridライブラリでは、メール送信のためにAPIキーを利用します。APIキーはダッシュボードで作成することができます。

API Keys

まだAPIキーを持っていない場合は新しく作成しましょう。作成に成功したら、表示される文字列を安全な場所にコピーしておきます。APIキーは一度しか表示されないのでご注意ください。

API Key Created

次に、.envファイルの環境変数にAPIキーを追加します。ファイルの末尾に以下を追記してください。

SENDGRID_API_KEY={YOUR API KEY}

データベースのセットアップ

次のステップは、データベースのセットアップです。このチュートリアルではMySQLを利用します。まだローカルマシンでMysqlの設定ができていない場合は、ダウンロードページにアクセスしてインストールを進めます。

アプリケーション用のデータベースを作成するには、MySQLクライアントへのログインが必要です。以下のコマンドを実行します。

$ mysql -u {your_user_name}

補足:MySQLインスタンスにパスワードを設定している場合は、コマンドに -p オプションを付けます。

以下のコマンドを実行し、データベースを作成します。

mysql> create database custom-mailing;
mysql> exit;

usersテーブルのマイグレーション

Laravelでは、次のような基本的なスキーマを含むusersテーブルのマイグレーションが最初から準備されています。

/**    * Run the migrations.
    *
    * @return void
    */
   public function up()
   {
       Schema::create('users', function (Blueprint $table) {
           $table->bigIncrements('id');
           $table->string('name');
           $table->string('email')->unique();
           $table->timestamp('email_verified_at')->nullable();
           $table->string('password');
           $table->rememberToken();
           $table->timestamps();
       });
   } 

このコードを見ると、本アプリケーションに必要なフィールド(emailname)が最初から存在するので、スキーマを編集する必要はありません。このマイグレーションはまだデータベースにコミットされていないため、以下のコマンドを実行します。

$ php artisan migrate

マイグレーションファイルのup()メソッドが実行されると、ファイルに列挙したフィールドを持つusersテーブルが作成されます。

Usersテーブルへの初期データの投入

テーブルが作成できたら、いくつかユーザ情報を登録しておきます。データの投入にはseedersを使うのが便利です。seederクラスを作るには、以下のコマンドを実行します。

$ php artisan make:seeder UsersTableSeeder

すると、database/seeds/UsersTableSeederというseederクラスが作成されます。このファイル( database/seeds/UsersTableSeeder.php )を開いて、以下のように編集しましょう。

<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Faker\Generator as Faker;
use Illuminate\Support\Facades\Hash;
class UsersTableSeeder extends Seeder
{
   /**
    * Run the database seeds.
    *
    * @return void
    */
   public function run(Faker $faker)
   {
       DB::table("users")->insert([
           [
               'name' => $faker->name,
               'email' => $faker->unique()->safeEmail, //use real email here
               'email_verified_at' => now(),
               'password' => Hash::make($faker->password()), // assword
           ],
           [
               'name' => $faker->name,
               'email' => $faker->unique()->safeEmail, //use real email here
               'email_verified_at' => now(),
               'password' => Hash::make($faker->password()), // password
           ],
           [
               'name' => $faker->name,
               'email' => $faker->unique()->safeEmail, //use real email here
               'email_verified_at' => now(),
               'password' => Hash::make($faker->password()), // password
           ],
       ]);
   }
}

補足:email fakerのメールアドレスは、実際にテストに使うアドレスへ置き換えておきます。

以下のコマンドを実行してデータを作成します。

$ php artisan db:seed --class=UsersTableSeeder

メール送信

ここまでの手順で、データベースのセットアップとデータの登録、SendGrid SDKのインストールができました。それでは、ビジネスロジックの実装に着手しましょう。まずは、メール送信機能を実装するcontrollerクラスが必要です。以下のコマンドを実行します。

$ php artisan make:controller MailingController

作成されたMailingController( app/Http/Controllers/MailingController.php )を以下のように編集します。

<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use SendGrid;
class MailingController extends Controller
{
   public function sendMail(Request $request)
   {
       $validated = $request->validate([
           'from' => 'required|email',
           'users' => 'required|array',
           'users.*' => 'required',
           'subject' => 'required|string',
           'body' => 'required|string',
       ]);
       $from = new \SendGrid\Mail\From($validated['from']);
       /* Add selected users email to $tos array */
       $tos = [];
       foreach ($validated['users'] as $user) {
           array_push($tos, new \SendGrid\Mail\To(json_decode($user)->email, json_decode($user)->name));
       }
       /* Sent subject of mail */
       $subject = new \SendGrid\Mail\Subject($validated['subject']);
       /* Set mail body */
       $htmlContent = new \SendGrid\Mail\HtmlContent($validated['body']);
       $email = new \SendGrid\Mail\Mail(
           $from,
           $tos,
           $subject,
           null,
           $htmlContent
       );
       /* Create instance of Sendgrid SDK */
       $sendgrid = new SendGrid(getenv('SENDGRID_API_KEY'));
       /* Send mail using sendgrid instance */
       $response = $sendgrid->send($email);
       if ($response->statusCode() == 202) {
           return back()->with(['success' => "E-mails successfully sent out!!"]);
       }
       return back()->withErrors(json_decode($response->body())->errors);
   }
}

sendMail()のメソッドがメールを送るおまじないです!バリデーションに成功したら、SendGridのsend()メソッドにデータを渡す準備をします。ここでは、配列を使ってもライブラリのhelperクラスを使っても構いませんが、helperクラスを使った方が必要なオブジェクト(From, To, Subject, Content)を簡単に生成できます。

データの準備ができたら、リクエストボディに格納するオブジェクトを生成するためSendGrid\Mail\Mailクラスを使います。このクラスは引数を5つ取ります( from, to, subject, plainTextContent, htmlContent )。続くSendGridクラスのインスタンスは、先ほど準備したAPIキーを渡して初期化します。

ここまでできたら、send()メソッドを使って$tos配列に格納したメールを送信します。send()メソッドの引数は、先ほど生成したSendGrid\Mail\Mailクラスのオブジェクト1つのみです。send()メソッドはstatusCodebodyを含むレスポンスを返します。リクエストが成功すると202のstatusCodeが返り、送信成功のメッセージとともにsendmailビューへリダイレクトします。それ以外のコードが返ると、エラーメッセージとともに前のページへ戻ります。

ビューの構築

以上でメールの送信ロジックは完成です!後はユーザが操作する画面が必要です。ここでは、メールの情報を入力する簡単なフォームを準備します。デフォルトのウェルカムページ( resources/views/welcome.blade.php )を開き、以下の内容で置き換えましょう。

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <title>Custom Mail Portal With Sendgrid</title>
   <!-- Styles -->
   <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet"
       integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
</head>
<body>
   <div class="container">
       <div class="jumbotron">
           @if (session('success'))
           <div class="alert alert-success">
               {{ session('success') }}
           </div>
           @endif
           @if ($errors->any())
           <div class="alert alert-danger">
               <ul>
                   @foreach ($errors->all() as $error)
                   <li>{{ $error }}</li>
                   @endforeach
               </ul>
           </div>
           @endif
           <div class="row">
               <div class="col">
                   <div class="card">
                       <div class="card-header">
                           Send Custom Mail
                       </div>
                       <div class="card-body">
                           <form method="POST" action="/sendmail">
                               @csrf
                               <div class="form-group">
                                   <label>From</label>
                                   <input required name="from" value="{{getenv('MAIL_FROM')}}" class="form-control">                               </div>
                               <div class="form-group">
                                   <label>Subject</label>
                                   <input required name="subject" class="form-control">
                               </div>
                               <div class="form-group">
                                   <label>Select users to send mail to</label>
                                   <select required name="users[]" multiple class="form-control">
                                       @foreach ($users as $user)
                                       <option value="{{$user}}">{{$user->name}} - {{$user->email}}</option>
                                       @endforeach
                                   </select>
                               </div>
                               <div class="form-group">
                                   <label>Message</label>
                                   <textarea required name="body" class="form-control" rows="3"></textarea>
                               </div>
                               <button type="submit" class="btn btn-primary">Send Mail(s)</button>
                           </form>
                       </div>
                   </div>
               </div>
           </div>
       </div>
   </div>
</body>
</html>

selectタグについて詳しく見てみると、optionの値が$usersプロパティから取得されていることが分かります。このとき、$userのデータをビューに渡しているのではなく、web.phpを直接参照している形になります。これを変更するには、app/Http/Controllers/MailingController.phpに以下の内容を記載します。

public function index()
   {
       return view('welcome', ['users' => User::all()]);
   }

このメソッドは、usersテーブルの全データが格納された配列を持つsendmailビューを返します。

ルーティングの設定

以上で主要な機能は完成です。最後に、アプリケーションを正しく動作させるためルーティングを設定します。routes/web.phpを開き、以下のように編集してください。

<?php
use App\User;
use Illuminate\Support\Facades\Route;/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', 'MailingController@index');
Route::post('/sendmail', 'MailingController@sendMail');

アプリケーションのテスト

それでは、完成したLaravelプロジェクトをテストしてみましょう!以下のコマンドを実行します。

$ php artisan serve

このコマンドによって、Laravelアプリケーションがローカルホストの8000番ポートで起動します。ブラウザでコマンド実行後に表示されるリンクにアクセスすると、このような画面が表示されます。

アプリケーションのテスト

フォームに必要事項を入力して「Send Mails」ボタンを選択します。問題なければ、入力した内容が記載されたメールが指定した宛先に届きます。

終わりに

このチュートリアルでは、メール送信システムの構築方法と、Twilio SendGrid SDKを使って複数の宛先にメール送信する方法を学びました。今回のソースコードをおさらいしたい方は、Githubもチェックしてください。

また、未登録ユーザへのメール送信に対応することで、このアプリケーションをさらに進化させることができます。ぜひお試しください。

メールを成功の原動力に

開発者にもマーケターにも信頼されているメールサービスを利用して、
時間の節約、スケーラビリティ、メール配信に関する専門知識を手に入れましょう。