これからLaravelを使用してメールを送信したいという入門者を対象にできるだけ詳細にLaravelでのメール送信設定の解説を行っています。

シンプルな方法でのメール送信

Laravel 5.3以降に追加されたMailableクラスを使った方法しか最近のバージョンのマニュアルは記載がないので、最初はLaravel5.2のマニュアルを参考にシンプルな形でメールの送信確認を行います。

Mailableクラスが難しいわけではなく入門者にとっては複数のクラスを使用しないほうが理解するのが簡単なため、こちらの方法を先に紹介しています。

コントローラーの作成

メール送信の動作確認を行うためにweb.phpに/mailを追加します 。/mailにアクセスがあった場合の処理はMailSendController.phpコントローラーに記述します。MailSendController.phpはphp artisanコマンドで作成します。


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

Route::get('/mail', 'MailSendController');

 $ php artisan make:controller MailSendController

作成したMailSendController.phpに下記を記述します。メールアドレスabc987@example.comの宛先にメールタイトルがThis is a test mailのメールを送信する設定を行なっています。


namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Mail;

class MailSendController extends Controller
{
    public function send(){

    	$data = [];

    	Mail::send('emails.test', $data, function($message){
    	    $message->to('abc987@example.com', 'Test')
            ->subject('This is a test mail');
    	});
    }
}

Mailファサードについて

Mailファサードのsendメソッドは下記のように3つの引数を取ることができます。


send(view_name, data, callback);
  • view_nameは、メールの本文の内容を記述するビューの名前です。htmlタグが使えます。
  • dataはビューに渡す変数です。
  • callbackはメッセージインスタンスを受け取るクロージャ()です。メッセージインスタンスはto, from, cc, subjectなどのメソッドを持っています。詳しくはメッセージインスタンスのマニュアルを確認してください。

toにはメールの送信先、subjectにはメールの件名を設定しています。

resourceの下にviews/emailsディレクトリ、その下にtest.blade.phpファイルを作成してメールの本文の内容を記述します。


<p>テストメールの送信です。</p>

送信内容をログへ書き出し

メールの送信設定(サーバやメールアカウント)を行わなければいけませんが、サーバからのメール送信になると不安になる人もいると思うので、まずはLaravelのログにメール内容を表示させる設定を行います。Laravelの環境設定ファイルである.envファイルを開いてMAIL_DRIVERをデフォルトのsmtpからlogに変更してください。


MAIL_DRIVER=log

設定は完了したのでphp artisan serveで開発用サーバを起動します。


$ php artisan serve
実際にサーバでLaravelを稼働している場合は、configの設定変更を反映させるためにphp artisan config:cacheコマンドを実施してください。

サーバが起動したら、/mailにアクセスしてください。そのあと画面に何も表示されなければ/storage/logsの下にあるlaravel-日付.logファイルを開いてください。

laravel-日付.logファイルに下記のように送信されたメールの内容が表示されているか確認してください。FromのExample<hello@example.com>以外は設定した内容になっていることが確認できます。

その他に送信するメールのContent-Typeからhtmlメールであることと文字コードはutf-8であることがわかります。


[2019-06-30 13:31:41] local.DEBUG: Message-ID: <69b6e70e2d1d2328be63631245ac4d67@127.0.0.1>
Date: Sun, 30 Jun 2019 13:31:41 +0000
Subject: This is a test mail
From: Example <hello@example.com>
To: Test <abc987@example.com>
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<p>テストメールの送信です。</p>

実際のメールサーバを利用した送信

ログへのメール内容の書き出しが正常に行われることが確認できたので、実際にメールを送信します。送信するメールサーバ、ユーザアカウント、パスワードの情報が必要になります。それらの情報は環境によって異なるため、管理者に確認を行う必要があります。それらの情報を.envファイルのメール関連のパラメータを使って設定します。設定が反映されない場合は、configのキャッシュを一度削除するためphp artisan config:cacheを実行してください。


MAIL_DRIVER=smtp
MAIL_HOST=XXXXX.jp
MAIL_PORT=587
MAIL_USERNAME=XXXXX@XXXXX.co.jp
MAIL_PASSWORD=XXXXX
MAIL_ENCRYPTION=null

.envファイル設定後、MailSendControllerに設定したtoのメールアドレスも実在するメールアドレスに変更を行なってください。

ここで利用するサーバの情報はMAIL_ENCRYPTIONも含めOUTLOOKなど普段使用しているメールクライアントソフトで設定しているものと同じです。Laravelのための特別な設定ではありません。

ブラウザから/mailにアクセスするとメールが送信されます。メールが受信されているか確認を行なってください。メールの送信元のFromがhello@example.comになっているので、MailSendCotrollerにfromメソッドを追加する必要があります。再度メールを送信するとFromも設定値が反映されていることを確認することができます。


$data = [];

Mail::send('emails.test', $data, function($message){
    $message->to('XXXXX@XXXXX.co.jp', 'Test')
    	    ->from('XXXXX@XXXXX.co.jp','Reffect')
    	    ->subject('This is a test mail');

Fromのデフォルト値はconfig/mail.phpに記述されています。.envにMAIL_FROM_ADDRESSとMAIL_FROM_NAMEを追加し指定することでFromのメールアドレスを固定することができます。


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

Gmailを利用したメール送信

Gmailのsmtpを利用してLaravelからメールを送信することができます。

Gmailを利用するために安全性の低いアプリのアクセス許可をオンにする設定するか2段階認証を利用する方法があります。どちらも説明しますが、設定が簡易は安全性の低いアプリのアクセス許可をオンにするのはGoogleでは推奨されていません。

安全性の低いアプリのアクセス許可による送信

.envファイルをGmailのアカウント情報に変更する必要があります。MAIL_USERNAMEとMAIL_PASSWORDは各自のGmailアカウントの情報となります。


MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=XXXXX@gmail.com
MAIL_PASSWORD=XXXXXXXX
MAIL_ENCRYPTION=ssl

上記の設定でメールの送信を行うとエラーが発生し、Googleアカウントのメールボックスには重大なセキュリティ通知という件名で下記のようなメールが届きます。Laravel側にもエラーが発生しており、メール送信は失敗しています。

ログインのブロックつまり、smtp経由で設定した情報でログインを試みようとしていますが、ログインする前にGmailによりログインがはじかれています。

Gmailログインブロック
Gmailログインブロック

アクティビティを確認をクリックして、はい、心当たりがありますをクリックしておきます。Laravelで接続設定をしただけでは不審なアプリと判断され、ログインが許可されません。許可を与えるためにセキュリティの設定を変更する必要があります。

ログインブロックに対応
ログインブロックに対応

Gmailのセキュリティ設定

Gmailのアカウントの設定からセキュリティを選択し、安全性の低いアプリのアクセスの設定画面を開きます。デフォルトではオフになっているので、オンにする必要があります。アクセスを有効にする(非推奨)をクリックしてください。

Gmailのセキュリティ設定
Gmailのセキュリティ設定
安全性の低いアプリの設定をON
安全性の低いアプリの設定をON

ONにするとGmailに先ほどと同じように重大なセキュリティ通知メールが届きます。内容は、安全性の低いアプリのアクセスが有効になりましたという設定変更の通知です。アクティビティを確認して、はい、心当たりがありますを選択してください。

これで安全性の低いアプリのアクセスがONになったので、メールを送信することができます。

テストの動作確認で安全性の低いアプリのアクセスをONにした場合は動作確認完了後、OFFに戻してください。また次の2段階認証設定を利用する場合もこの設定は必要ないので、OFFに戻しておいてください。

2段階認証設定によるメールの送信

Gmailにログインする際の2段階認証の設定を行っていない人は下記のように2段階認証プロセスがオフになっています。

2段階認証の設定確認
2段階認証の設定確認

オフの場合は設定をオンにする必要があります。詳しい説明はここでは行いませんが、設定をオンにしてください。オンにしていない人はLaravelからメール送信をするしないに関わらずセキュリティのことを考えるとオンにしておきましょう。設定には電話番号が必要になります。

アプリパスワードの設定

設定が完了すると2段階認証プロセスがオンになり、アプリパスワードという項目が表示されます。

2段階認証がオンになった画面
2段階認証がオンになった画面

アプリパスワードを選択してください。

アプリケーションパスワード設定
アプリケーションパスワード設定

アプリの選択をメールにし、デバイスの選択に任意の名前をつけて生成ボタンをクリックすると16桁のパスワードが表示されます。使い方をしっかり読んでください。

16桁のアプリケーションパスワード
16桁のアプリケーションパスワード

Laravelの.envファイルを開いて、先程設定していたUSER_PASSWODの設定をこの16桁のパスワードに変更します。

設定変更後は、php artisan config:cacheを実行されば、Gmailからメールを送信することができます。

Gmail を経由していメールを送信する場合、fromで設定していたメールアドレスはGmailのメールアカウントのXXXXX@gmail.comで送信されます。Gmailの設定で他のメールアドレスを追加することで変更できそうですが、未実施のため変更方法はできないかもしれません。

Mailableクラスを使用したメール送信

Mailableクラスの作成

Mailableクラスを利用してメールの送信を行います。php artisan make:mailコマンドで作成します。


$ php artisan make:mail SendTestMail
Mail created successfully

Maiableファイルはapp¥Mailディレクトリの下に作成され、中身は下記の通りです。


<?php

namespace App\Mail;

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

class SendTestMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

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

これまでと全く同じ内容のテストメールを送るため、SendTestMail.phpのbuildメソッドを下記のように書き換えます。


public function build()
{
    return $this->view('emails.test')
                ->from('XXX@XXXX','Test')
                ->subject('This is a test mail');
}

MailSendController.phpでは以下のように書き換えが必要になります。


namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Mail\SendTestMail;

use Mail;

class MailSendController extends Controller
{
    public function send(){

	$to = [
	    [
	        'email' => 'XXXXX@XXXXX.jp', 
	        'name' => 'Test',
	    ]
	];

	Mail::to($to)->send(new SendTestMail());

    }
}

この設定でブラウザで/mailにアクセスするとメールが送信されます。

HTMLメール or テキストメール

これまではメールを送信する時にviewメソッドでビューファイルを指定し、htmlとして送信を行っていましたがテキストメールでも送信を行うことができます。viewメソッドをtextメソッドに変更して、ビューのファイルの内容をテキスト形式に変更します。


public function build()
{
    return $this->text('emails.test_text')
                ->from('XXX@XXXX','Reffect')
                ->subject('This is a test mail');
}

views/emailsの下にtest_text.blade.phpファイルを作成し下記を記述します。


This is a test mail

これは初めてのメールです。

メールクライアントで見ると改行も行われて記述どおりの内容が送信されていることが確認できます。

メールクライアントで確認
メールクライアントで確認

ヘッダーのcontent-typeを確認するとtext/plainであることも確認できます。HTMLメールだとcontent-typeはtext/htmlになります。

textとhtmlのマルチパートでも送ることができます。


public function build()
{
    return $this->text('emails.test_text')
          ->view('emails.test')
                ->from('XXX@XXXX','Reffect')
                ->subject('This is a test mail');
}

受信したメールクライアントでヘッダーのContent-Typeを確認し、multipart/alternativeになっていればhtmlとtext形式どちらでも送信されていることが確認できます。

複数人にメールを送る場合

一度に複数人の人にメールを送信する場合は下記のように配列を使用します。


$to = ['AAA@XXXXX','BBB@XXXXX'];

Mail::to($to)->send(new SendTestMail());

メールにエイリアスをつけたい場合は次のように行うことができます。


$to = [
    [
        'email' => 'AAA@XXXXX', 
        'name' => 'Test',
    ],	    
    [
        'email' => 'BBB@XXXXX', 
        'name' => 'Test2',
    ],
];

$toにはcollectionを使用することができます。つまりusersテーブルから取得したユーザ情報をそのまま$toに渡すことができます。


$to = User::all();

Mail::to($to)->send(new SendTestMail());

usersテーブルには、ユーザの登録が必要です。ここではUser::all()を使用していますが、実際はwhere句を利用して送信するユーザを選択してください。usersテーブルのemail、nameの列が使用されます。

bccやccについては、Mailableクラスの中で設定を行いますが、設定方法はtoの場合と同じです。


public function build()
{
    return $this->text('emails.test_text')
                ->from('XXX@XXXXX','Reffect')
                ->subject('This is a test mail')
                ->cc('XXX@XXXXXX')
                ->bcc('XXX@XXXXXX');
}

ビューに変数を渡す

データベースに保存されたテーブルから取得したデータをメールの内容に渡すためには変数を利用する必要があります。

usersテーブルに登録されたユーザ情報を利用して動作確認を行います。変数は、MailableクラスのSendTestMailをインスタンス化する時に渡すことができます。


$user = User::find(1);

Mail::to($user)->send(new SendTestMail($user));

SendTestMailのbuildメソッドでwithを利用して変数を渡します。


    public function __construct($user)
    {
        $this->user = $user;
    }

    public function build()
    {
        return $this->text('emails.test_text')
                    ->from('XXX@XXXXX','Reffect')
                    ->subject('This is a test mail')
                    ->with(['user' => $this->user]);
    }

test_text.blade.phpは{{ }}を利用して値を展開することができます。


{{ $user->name }} 様

{{ $user->email }}からのログインが確認されました。

ご本人によるアクセスか確認してください。

この設定でメールを送信すると{{ }}の中に$user->nameと$user->emailの値に置き換えられて送信されます。

ローカルファイルを添付する

ローカルファイルに保存されているファイルを添付する方法を確認します。ローカルのファイルを添付するためには、事前にファイルをローカルに保存しておく必要があります。

Laravelでのファイルのアップロード方法を知りたい場合は、下記を参照してください。

アップロードしたファイルの保存先はstorage/appの下なのでその直下のpdfディレクトリに添付するファイルが保存されている状態で話を進めます。

メールにファイルを添付するためには、attachメソッドを追加します。attachメソッドに添付するファイルのパスを設定することでメールへのファイル添付を行うことができます。

SendTestMailのbuildメソッドでattachを利用してファイルを添付します。


public function build()
{
    return $this->text('emails.test_text')
                ->from('XXX@XXXXX','Reffect')
                ->subject('This is a test mail')
                ->with(['user' => $this->user])
                ->attach(storage_path('app/pdf/test_1.pdf'));
}

上記ではLaravelのhelper関数のstorage_pathを利用してファイルのパスを設定しています。storage_pathの戻り値は各環境で異なりますが、storageまでのフルパスを取得することができます。pdfファイルはstorage/app/pdfの下に保存されているので、storage(‘app/pdf/test_1.pdf’)を設定しています。

storage_pathがどこの場所のパスなのかわからない場合は、dd(storage_path(”))を実行して確かめてください。

メールを送信するとファイルが添付されて送られます。

.envファイルのMAIL_DRIVERをlogに設定してログを見るとPDFの場合は下記のようにファイルの内容がテキストで表示されます。ファイルの内容によってはかなりの行になります。


Content-Type: application/pdf; name=test_1.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=test_1.pdf

%PDF-1.3
1 0 obj
<< /Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R >>

複数のファイルを添付する

複数のファイルをメールに添付したい場合は複数のattachをつけることで対応することができます。


public function build()
{
    return $this->text('emails.test_text')
                ->from('XXX@XXXXX','Reffect')
                ->subject('This is a test mail')
                ->with(['user' => $this->user])
                ->attach(storage_path('app/pdf/test_1.pdf'));
                ->attach(storage_path('app/pdf/test_2.pdf'));
}

さらにファイルを添付したいという場合にはattachを増やしていくのは現実的ではありません。foreachを組み合わせて添付を行います。

下の例では$filesの配列をパスを入れているのでattachよりよくなっているわけではございません。foreachを展開する点に値注目してください。これは配列だけではなくテーブルから取得したcollectionでも活用できます。

public function build()
{
    $files = [storage_path('app/pdf/test_1.pdf'),
              storage_path('app/pdf/test_2.pdf'),
              storage_path('app/pdf/test_3.pdf'),
              storage_path('app/pdf/test_4.pdf'),
              storage_path('app/pdf/test_5.pdf'),
              storage_path('app/pdf/test_6.pdf')];

    $mail = $this->text('emails.test_text')
                ->from('XXX@XXXXX','Reffect')
                ->subject('This is a test mail')
                ->with(['user' => $this->user]);


    foreach($files as $file){
        $mail->attach($file);
    }

    return $mail;
}