Mailableクラスを使ってMail送信機能を実装

個人的な学習でLaravelのMailableクラスを使用してMail送信機能についてまとめてみました。

MailableクラスはLaravel 5.3から使用することができます。

僕自身が書いたコードはこちら

github.com

環境

今回は Laravel5.6.x、PHPは7.2.xを使用しています。

ドライバ

Laravelでは、APIベースのドライバであるMailgun、SparkPost、Amazon SESを使用することができ、かつSMTPよりも高速に動作します。今回はAmazon SESを使用していきます。

まずはこれらのAPIドライバを使用するために、ComposerよりGuzzle HTTPライブラリをインストールしていきます。

$ composer require guzzlehttp/guzzle

さらにAmazon SESドライバを使用する場合は、Amazon AWS SDK for PHPのインストールが必要となります。 comporser.jsonrequireセクションを以下のように編集。

"require": {
    "php": "^7.1.3",
    "fideloper/proxy": "^4.0",
    "guzzlehttp/guzzle": "^6.3",
    "laravel/framework": "5.6.*",
    "laravel/tinker": "^1.0",
    "aws/aws-sdk-php": "~3.0"  // 追加
},

composer updateを実行します。

次にconfig/mail.phpのdriverオプションをsesに設定します。デフォルトでは以下のようになっていて、こちらに合わせて.envを編集します。

'driver' => env('MAIL_DRIVER', 'smtp'),

config/services.phpも同じで、以下のようになってる箇所を.envから指定していきます。

'ses' => [
    'key' => env('SES_KEY'),
    'secret' => env('SES_SECRET'),
    'region' => env('SES_REGION', 'us-east-1'),
],

.envで最低限、以下の項目が指定されていれば実際に動かすことができました。

MAIL_DRIVER=ses
SES_KEY=
SES_SECRET=
SES_REGION=

Amazon SESに関してはこちらを参考にさせて頂きました。

dev.classmethod.jp

Mailableクラス

アプリケーションから送信されるMailの各種設定をMailableクラスの方で行います。 make:mailコマンドを使用し、Mailableクラスを生成していきます。

$ php artisan make:mail OrderShipped

生成されたクラスのbuildメソッド内で各種設定を行います。

送信元の設定

fromメソッドを使用して送信元を設定します。

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->from('example@example.com');
}

アプリケーションで同じ"from"アドレスを全メールで使用するのであれば、config/mail.phpでグローバルに指定することもできます。

'from' => [
    'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
    'name' => env('MAIL_FROM_NAME', 'Example'),
],

こちらに合わせて、.envを編集していきます。

また、Amazon SESを使用する場合、送信元の設定はAmazon SESで登録した送信メールアドレス(送信者認証を行ったメールアドレス)を登録しなければなりません。

ビューの設定

Mailableクラスのbuildメソッドの中で、viewメソッドを使用してviewを設定していきます。 メールの中身もBladeのテンプレートエンジンを使用したviewを使うことができます。

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->view('emails.orders.shipped');
}

viewにデータを渡す

withメソッドを使いviewにデータを渡すことができます。

<?php

namespace App\Mail;

use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * @var
     */
    protected $order;

    // 新しいメッセージインスタンスの生成
    /**
     * OrderShipped constructor.
     *
     * @param Order $order
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped')
            ->with([  // こちらでview側にデータを渡している
                'orderName' => $this->order->name,
                'orderPrice' => $this->order->price,
            ]);
    }
}

今回は適当に以下のようなviewを作成してデータを受け取るようにしています。

resources/views/emails/orders.shipped.blade.php

<p>{{$orderName}}さん</p>
<p>{{$orderPrice}}円のお支払いです。</p>

メールの送信

Mailファサードtoメソッドを使い、宛先を指定することができます。 引数に直接メールアドレスを指定することも可能ですし、ユーザーインスタンス、もしくはユーザーのコレクションを指定することもできます。

Mailableクラスのインスタンスsendメソッドへ渡すことで、メールを送信させることができます。

<?php

namespace App\Http\Controllers;

use App\Order;
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

class OrderController extends Controller
{
    public function ship($orderId)
    {
        $order = Order::findOrFail($orderId);

        Mail::to('hello@example.com')->send(new OrderShipped($order));

        return redirect('/');
    }
}

routeも以下のように追加し、

<?php

Route::get('/', function () {
    return view('welcome');
});

Route::get('order/{orderId}', 'OrderController@ship');  // 追加

適当にOrderインスタンスをtinkerなどから作成して、

/order/1にアクセスすると f:id:rnakamine:20181219092342p:plain

メールが送信されてることを確認できました!!

まとめ

Mailableクラスを使用することで、比較的簡単にMail送信機能を実装することができます。

Mailファサードqueueメソッドを使うことによってレスポンスの時間を待たず、バックグラウンドで処理(非同期)したりできるようなので、次回試してみます。