イントロダクション
メール送信を複雑にする必要はありません。Laravelは、ポピュラーなSymfony
Mailerコンポーネントによる、クリーンでシンプルなメールAPIを提供しています。LaravelとSymfony
Mailerは、SMTP、Mailgun、Postmark、Amazon
SES、sendmail
経由でメールを送信するドライバを提供しており、ローカルまたはクラウドベースのサービスを通じて、すぐにメール送信を開始できます。
設定
Laravelのメールサービスは、アプリケーションのconfig/mail.php
設定ファイルを介して設定できます。このファイル内で設定された各メーラーには、独自の設定と独自の「トランスポート」があり、アプリケーションがさまざまな電子メールサービスを使用して特定の電子メールメッセージを送信できるようにします。たとえば、アプリケーションでPostmarkを使用してトランザクションメールを送信し、AmazonSESを使用して一括メールを送信するなどです。
mail
設定ファイル内に、mailers
設定配列があります。この配列には、Laravelがサポートしている主要なメールドライバ/トランスポートごとのサンプル設定エントリが含まれています。その中でdefault
設定値は、アプリケーションが電子メールメッセージを送信する必要があるときにデフォルトで使用するメーラーを決定します。
ドライバ/トランスポートの前提条件
MailgunやPostmarkなどのAPIベースドライバは、SMTPサーバを経由してメールを送信するよりもシンプルで高速です。可能であれば、こうしたドライバのいずれかを使用することをお勧めします。
Mailgunドライバ
Mailgunドライバを使用する場合は、Composerで、SymfonyのMailgun Mailerトランスポートをインストールします。
composer require symfony/mailgun-mailer symfony/http-client
次に、アプリケーションのconfig/mail.php
設定ファイルにある、default
オプションをmailgun
に設定します。アプリケーションのデフォルトメーラーを設定したら、config/services.php
設定ファイルへ以下のオプションがあることを確認してください。
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
米国のMailgunリージョンを使用していない場合は、services
設定ファイルでリージョンのエンドポイントを定義できます。
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),
],
Postmarkドライバ
Postmarkドライバを使用する場合は、Composerを使い、SymfonyのPostmark Mailerトランスポートをインストールします。
composer require symfony/postmark-mailer symfony/http-client
次に、アプリケーションのconfig/mail.php
設定ファイルのdefault
オプションをpostmark
へ設定します。アプリケーションのデフォルトメーラーを設定したら、config/services.php
設定ファイルへ以下のオプションがあることを確認してください。
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
特定のメーラで使用する必要があるPostmarkメッセージストリームを指定したい場合は、message_stream_id
設定オプションをメーラの設定配列に追加してください。この設定配列は、アプリケーションのconfig/mail.php
設定ファイルにあります。
'postmark' => [
'transport' => 'postmark',
'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
],
この方法で、メッセージストリームが異なる複数のPostmarkメーラを設定することもできます。
SESドライバ
Amazon SESドライバを使用するには、最初にAmazon AWS SDK for PHPをインストールする必要があります。このライブラリは、Composerパッケージマネージャを使用し、インストールできます。
composer require aws/aws-sdk-php
次に、config/mail.php
設定ファイルのdefault
オプションをses
に設定し、config/services.php
設定ファイルに以下のオプションがあることを確認してください。
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
AWSの一時的な認証情報をセッショントークン経由で利用するには、アプリケーションのSES設定へtoken
キーを追加します。
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'token' => env('AWS_SESSION_TOKEN'),
],
Laravelがメール送信時に、AWS
SDKのSendEmail
メソッドへ渡す、追加オプションを定義したい場合は、ses
設定にoptions
配列を定義します。
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'options' => [
'ConfigurationSetName' => 'MyConfigurationSet',
'EmailTags' => [
['Name' => 'foo', 'Value' => 'bar'],
],
],
],
フェイルオーバー設定
アプリケーションのメールを送信するように設定した外部サービスがダウンすることがあります。このような場合には、プライマリ配信ドライバがダウンした場合に使用する、1つ以上のバックアップメール配信設定を定義できると便利です。
これを実現するには、アプリケーションのmail
設定ファイルで、failover
トランスポートを使用するメーラーを定義する必要があります。アプリケーションのfailover
メーラー設定配列に、配送に使うメールドライバを選択する順序を規定するmailers
の配列を含める必要があります。
'mailers' => [
'failover' => [
'transport' => 'failover',
'mailers' => [
'postmark',
'mailgun',
'sendmail',
],
],
// ...
],
フェイルオーバーメーラーを定義したら、アプリケーションのmail
設定ファイル内のdefault
設定キーの値に、その名前を指定して、このメーラーをアプリケーションが使用するデフォルトメーラーとして設定する必要があります。
'default' => env('MAIL_MAILER', 'failover'),
Mailableの生成
Laravelアプリケーションを構築する場合、アプリケーションが送信する各タイプの電子メールは"Mailable"クラスとして表します。これらのクラスはapp/Mail
ディレクトリに保存されます。アプリケーションにこのディレクトリが存在しなくても心配ありません。make:mail
Artisanコマンドを使用して最初のメール可能なクラスを作成するときに、生成されます。
php artisan make:mail OrderShipped
Mailableの記述
Mailableクラスを生成したら、それを開いて、その内容を調べてください。まず、メール可能なクラスの設定はすべてbuild
メソッドで行われることに注意してください。このメソッド内でfrom
、subject
、view
、attach
などのさまざまなメソッドを呼び出して、電子メールの表示と配信を設定できます。
Tip!! Mailableの
build
メソッドではタイプヒントで依存を指定できます。Laravelのサービスコンテナは、これらの依存を自動的に注入します。
Senderの設定
from
メソッドの使用
まず、メールの送信者の設定について見ていきましょう。言い換えると、電子メールを送信したのは誰かです。送信者を設定するには2つの方法があります。まず、Mailableクラスのbuild
メソッド内でfrom
メソッドを使用する方法です。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->from('example@example.com', 'Example')
->view('emails.orders.shipped');
}
グローバルfrom
アドレスの使用
ただし、アプリケーションがすべての電子メールに同じ「送信者」アドレスを使用している場合、生成する各メール可能クラスでfrom
メソッドを呼び出すのは面倒です。代わりに、config/mail.php
設定ファイルでグローバルな「送信者」アドレスを指定できます。このアドレスは、Mailableクラス内で「送信者」アドレスを指定しない場合に使用します。
'from' => ['address' => 'example@example.com', 'name' => 'App Name'],
また、config/mail.php
設定ファイル内でグローバルな"reply_to"アドレスも定義できます。
'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'],
ビューの設定
Mailableクラスのbuild
メソッド内で、view
メソッドを使用して、電子メールのコンテンツをレンダするときに使用するテンプレートを指定できます。通常、各メールはBladeテンプレートを使用してコンテンツをレンダするため、メールのHTMLを作成するときにBladeテンプレートエンジンの能力と利便性を最大限に活用できます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
Tip!! すべてのメールテンプレートを格納するために
resources/views/emails
ディレクトリを作成することを推奨します。ただし、resources/views
ディレクトリ内ならば好きな場所へ自由に配置できます。
平文テキストの電子メール
電子メールの平文テキストバージョンを定義する場合は、text
メソッドを使用します。view
メソッドと同様に、text
メソッドは電子メールの内容をレンダするために使用するテンプレート名を引数に取ります。メッセージのHTMLバージョンと平文テキストバージョンの両方を自由に定義できます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->text('emails.orders.shipped_plain');
}
ビューデータ
Publicなプロパティ経由
通常、電子メールのHTMLをレンダするときに使用するデータをビューへ渡す必要があります。ビューでデータを利用できるようにする方法は2つあります。まず、Mailableクラスで定義したパブリックプロパティは、自動的にビューで使用できるようになります。したがって、たとえばMailableクラスのコンストラクタにデータを渡し、そのデータをクラスで定義したパブリックプロパティに設定できます。
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* 注文インスタンス
*
* @var \App\Models\Order
*/
public $order;
/**
* 新しいメッセージインスタンスの生成
*
* @param \App\Models\Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* メッセージを作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped');
}
}
データをパブリックプロパティへ設定すると、ビューで自動的に利用できるようになるため、Bladeテンプレートの他のデータにアクセスするのと同じようにアクセスできます。
<div>
Price: {{ $order->price }}
</div>
with
メソッド経由
テンプレートへ送信する前にメールのデータの形式をカスタマイズしたい場合は、with
メソッドを使用して手作業でデータをビューへ渡せます。通常、Mailableクラスのコンストラクターを介してデータを渡します。ただし、このデータをprotected
またはprivate
プロパティに設定して、データがテンプレートで自動的に使用可能にならないようにする必要があります。次に、with
メソッドを呼び出すときに、テンプレートで使用できるようにするデータの配列を渡します。
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* 注文インスタンス
*
* @var \App\Models\Order
*/
protected $order;
/**
* 新しいメッセージインスタンスの生成
*
* @param \App\Models\Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* メッセージを作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->with([
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
]);
}
}
データがwith
メソッドに渡されると、ビューで自動的に利用できるようになるため、Bladeテンプレートの他のデータにアクセスするのと同じようにアクセスできます。
<div>
Price: {{ $orderPrice }}
</div>
添付
電子メールに添付ファイルを追加するには、Mailableクラスのbuild
メソッド内でattach
メソッドを使用します。attach
メソッドは、ファイルへのフルパスを最初の引数に受けます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file');
}
メッセージにファイルを添付する場合、array
をattach
メソッドの2番目の引数に渡すことにより、表示名やMIMEタイプを指定することもできます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
ディスクからファイルを添付
ファイルシステムディスクのいずれかにファイルを保存している場合は、attachFromStorage
メソッドを使用してファイルを電子メールに添付できます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachFromStorage('/path/to/file');
}
必要に応じて、attachFromStorage
メソッドの2番目と3番目の引数を使用して、ファイルの添付ファイル名と追加オプションを指定できます。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachFromStorage('/path/to/file', 'name.pdf', [
'mime' => 'application/pdf'
]);
}
デフォルトのディスク以外のストレージディスクを指定する必要がある場合は、attachFromStorageDisk
メソッドを使用します。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachFromStorageDisk('s3', '/path/to/file');
}
素のデータの添付ファイル
attachData
メソッドを使用して、素のバイト文字列を添付ファイルとして添付できます。たとえば、メモリ内にPDFを生成し、ディスクに書き込まずに電子メールに添付する場合は、この方法を使用できます。attachData
メソッドは、最初の引数に素のデータバイトを取り、2番目の引数にファイルの名前、3番目の引数にオプションの配列を取ります。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
インライン添付
インライン画像をメールに埋め込むのは、通常面倒です。ただし、Laravelはメールに画像を添付する便利な方法を提供しています。インライン画像を埋め込むには、メールテンプレート内の$message
変数でembed
メソッドを使用します。Laravelは自動的に$message
変数をすべてのメールテンプレートで利用できるようにするので、手作業で渡すことを心配する必要はありません。
<body>
Here is an image:
<img src="{{ $message->embed($pathToImage) }}">
</body>
Note: 平文ンテキストメッセージはインライン添付ファイルを利用しないため、
$message
変数は平文テキストメッセージテンプレートでは使用できません。
素のデータの添付ファイルへの埋め込み
電子メールテンプレートに埋め込みたい素の画像データ文字列がすでにある場合は、$message
変数でembedData
メソッドを呼び出すことができます。embedData
メソッドを呼び出すときは、埋め込み画像に割り当てる必要のあるファイル名を指定する必要があります。
<body>
Here is an image from raw data:
<img src="{{ $message->embedData($data, 'example-image.jpg') }}">
</body>
Attachableオブジェクト
単純な文字列のパスを介してメッセージへファイルを添付すれば十分なことがある一方で、多くの場合、アプリケーション内の添付可能なエンティティはクラスによって表されます。例えば、アプリケーションがメッセージに写真を添付している場合、アプリケーションはその写真を表すPhoto
モデルを用意することもできます。その場合、Photo
モデルをattach
メソッドに渡せれば、便利ですよね?添付可能なAttachableオブジェクトを使用すれば、それが実行できます。
この機能を利用するには、メッセージへ添付できるオブジェクトに、Illuminate\Contracts\Mail\Attachable
インターフェイスを実装します。このインターフェイスは、そのクラスがIlluminate\Mail\Attachment
インスタンスを返すtoMailAttachment
メソッドを定義するよう指示します:
<?php
namespace App\Models;
use Illuminate\Contracts\Mail\Attachable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Mail\Attachment;
class Photo extends Model implements Attachable
{
/**
* Get the attachable representation of the model.
*
* @return \Illuminate\Mail\Attachment
*/
public function toMailAttachment()
{
return Attachment::fromPath('/path/to/file');
}
}
Once you have defined your attachable object, you may simply pass an
instance of that object to the attach
method when building
an email message:
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('photos.resized')
->attach($this->photo);
}
Of course, attachment data may be stored on a remote file storage service such as Amazon S3. So, Laravel also allows you to generate attachment instances from data that is stored on one of your application's filesystem disks:
// Create an attachment from a file on your default disk...
return Attachment::fromStorage($this->path);
// Create an attachment from a file on a specific disk...
return Attachment::fromStorageDisk('backblaze', $this->path);
In addition, you may create attachment instances via data that you
have in memory. To accomplish this, provide a closure to the
fromData
method. The closure should return the raw data
that represents the attachment:
return Attachment::fromData(fn () => $this->content);
Laravel also provides additional methods that you may use to
customize your attachments. For example, you may use the as
and withMime
methods to customize the file's name and MIME
type:
return Attachment::fromPath('/path/to/file')
->as('Photo Name')
->withMime('image/jpeg');
タグとメタデータ
MailgunやPostmarkなどのサードパーティのメールプロバイダーは、メッセージの「タグ」や「メタデータ」をサポートしており、アプリケーションから送信されたメールをグループ化して追跡するために使用することができます。タグやメタデータは、tag
メソッドやmetadata
メソッドにより、メールメッセージへ追加できます。
/**
* メッセージの構築
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->tag('shipment')
->metadata('order_id', $this->order->id);
}
アプリケーションでMailgunドライバを使用している場合、タグとメタデータの詳細は、Mailgunのドキュメントを参照してください。同様に、Postmarkのドキュメントも、タグとメタデータのサポートについて、詳しい情報を得るために参照できます。
アプリケーションがAmazon
SESを使用してメールを送信している場合、metadata
メソッドを使用して、メッセージへSES
「タグ」を添付する必要があります。
Symfonyメッセージのカスタマイズ
Mailable
ベースクラスのwithSymfonyMessage
メソッドは、メッセージ送信前にSymfonyのメッセージインスタンスで呼び出されるクロージャを登録可能です。これにより、メッセージが配信される前に、メッセージを詳細にカスタマイズする機会が得られます。
use Symfony\Component\Mime\Email;
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
$this->view('emails.orders.shipped');
$this->withSymfonyMessage(function (Email $message) {
$message->getHeaders()->addTextHeader(
'Custom-Header', 'Header Value'
);
});
return $this;
}
Markdown Mailable
Markdown Mailableメッセージを使用すると、Mailableでメール通知の事前に作成されたテンプレートとコンポーネントを利用できます。メッセージはMarkdownで記述されているため、Laravelはメッセージの美しくレスポンシブなHTMLテンプレートをレンダすると同時に、平文テキスト版も自動的に生成できます。
Markdown Mailableの生成
対応するMarkdownテンプレートを使用してMailableファイルを生成するには、make:mail
Artisanコマンドの--markdown
オプションを使用します。
php artisan make:mail OrderShipped --markdown=emails.orders.shipped
次に、Mailableオブジェクトをそのbuild
メソッド内で設定するときに、view
メソッドの代わりにmarkdown
メソッドを呼び出します。markdown
メソッドは、Markdownテンプレートの名前と、テンプレートで使用するデータ配列をオプションとして引数に取ります。
/**
* メッセージの作成
*
* @return $this
*/
public function build()
{
return $this->from('example@example.com')
->markdown('emails.orders.shipped', [
'url' => $this->orderUrl,
]);
}
Markdownメッセージの記述
Markdown Mailableは、BladeコンポーネントとMarkdown構文の組み合わせを使用して、Laravelに組み込まれた電子メールUIコンポーネントを活用しながら、メールメッセージを簡単に作成できるようにします。
@component('mail::message')
# 発送
注文を発送しました。
@component('mail::button', ['url' => $url])
注文の確認
@endcomponent
Thanks,<br>
{{ config('app.name') }}
@endcomponent
Tip!! Markdownメールを書くときに余分なインデントを使用しないでください。Markdown標準に従って、Markdownパーサーはインデントされたコンテンツをコードブロックとしてレンダリングします。
ボタンコンポーネント
ボタンコンポーネントは、中央に配置されたボタンリンクをレンダします。コンポーネントは、url
とオプションのcolor
の2つの引数を取ります。サポートしている色は、primary
、success
、error
です。メッセージには、必要なだけのボタンコンポーネントを追加できます。
@component('mail::button', ['url' => $url, 'color' => 'success'])
注文の確認
@endcomponent
パネルコンポーネント
パネルコンポーネントは、メッセージの残りの部分とはわずかに異なる背景色を持つパネルで、指定するテキストのブロックをレンダします。これにより、特定のテキストブロックに注意を引くことができます。
@component('mail::panel')
ここはパネルの本文。
@endcomponent
テーブルコンポーネント
テーブルコンポーネントを使用すると、MarkdownテーブルをHTMLテーブルに変換できます。コンポーネントは、そのコンテンツとしてMarkdownテーブルを受け入れます。テーブルの列の配置は、デフォルトのMarkdownテーブルの配置構文をサポートします。
@component('mail::table')
| Laravel | テーブル | 例 |
| ------------- |:-------------:| --------:|
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
@endcomponent
コンポーネントのカスタマイズ
カスタマイズするために、すべてのMarkdownメールコンポーネントを自身のアプリケーションへエクスポートできます。コンポーネントをエクスポートするには、vendor:publish
Artisanコマンドを使用してlaravel-mail
アセットタグでリソース公開します。
php artisan vendor:publish --tag=laravel-mail
このコマンドは、Markdownメールコンポーネントをresources/views/vendor/mail
ディレクトリへリソース公開します。mail
ディレクトリにはhtml
ディレクトリとtext
ディレクトリが含まれ、それぞれに利用可能なすべてのコンポーネントのそれぞれの表現が含まれます。これらのコンポーネントは自由にカスタマイズできます。
CSSのカスタマイズ
コンポーネントをエクスポートした後、resources/views/vendor/mail/html/themes
ディレクトリにはdefault.css
ファイルが含まれます。このファイルのCSSをカスタマイズすると、MarkdownメールメッセージのHTML表現内でスタイルが自動的にインラインCSSスタイルに変換されます。
LaravelのMarkdownコンポーネント用にまったく新しいテーマを作成したい場合は、CSSファイルをhtml/themes
ディレクトリに配置できます。CSSファイルに名前を付けて保存した後、アプリケーションのconfig/mail.php
設定ファイルのtheme
オプションを更新して、新しいテーマの名前と一致させます。
個々のMailableのテーマをカスタマイズするには、Mailableクラスの$theme
プロパティを、そのMailableを送信するときに使用するテーマの名前に設定します。
メール送信
メッセージを送信するには、Mail
ファサードでto
メソッドを使用します。to
メソッドは、電子メールアドレス、ユーザーインスタンス、またはユーザーのコレクションを受け入れます。オブジェクトまたはオブジェクトのコレクションを渡すと、メーラーは電子メールの受信者を決定するときに自動的にemail
およびname
プロパティを使用するため、これらの属性がオブジェクトで使用可能であることを確認してください。受信者を指定したら、Mailableクラスのインスタンスをsend
メソッドに渡すことができます。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Mail\OrderShipped;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class OrderShipmentController extends Controller
{
/**
* 指定注文を発送
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$order = Order::findOrFail($request->order_id);
// 注文の発送処理…
Mail::to($request->user())->send(new OrderShipped($order));
}
}
メッセージを送信するときに「宛先」の受信者を指定するだけに限定されません。それぞれのメソッドをチェーン化することで、「to」、「cc」、「bcc」の受信者を自由に設定できます。
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
受信者をループする
場合によっては、受信者/電子メールアドレスの配列を反復処理して、受信者のリストにMailableファイルを送信する必要が起きるでしょう。しかし、to
メソッドはメールアドレスをMailable受信者のリストに追加するため、ループを繰り返すたびに、以前のすべての受信者に別のメールが送信されます。したがって、受信者ごとにMailableインスタンスを常に再作成する必要があります。
foreach (['taylor@example.com', 'dries@example.com'] as $recipient) {
Mail::to($recipient)->send(new OrderShipped($order));
}
特定のメーラーを介してメールを送信
デフォルトでは、Laravelはアプリケーションのmail
設定ファイルでdefault
メーラーとして設定されたメーラーを使用してメールを送信します。しかし、mailer
メソッドを使用して、特定のメーラー設定を使用してメッセージを送信することができます。
Mail::mailer('postmark')
->to($request->user())
->send(new OrderShipped($order));
メールのキュー投入
メールメッセージのキュー投入
電子メールメッセージの送信はアプリケーションのレスポンス時間に悪影響を与える可能性があるため、多くの開発者はバックグラウンド送信のために電子メールメッセージをキューに投入することを選択します。Laravelは組み込みの統一キューAPIを使用してこれを簡単にしています。メールメッセージをキューに投入するには、メッセージの受信者を指定した後、Mail
ファサードでqueue
メソッドを使用します。
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue(new OrderShipped($order));
このメソッドは、メッセージがバックグラウンドで送信されるように、ジョブをキューへ自動的に投入処理します。この機能を使用する前に、キューを設定しておく必要があります。
遅延メッセージキュー
キューに投入した電子メールメッセージの配信を遅らせたい場合は、later
メソッドを使用します。later
メソッドは最初の引数にメッセージの送信時期を示すDateTime
インスタンスを取ります。。
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->later(now()->addMinutes(10), new OrderShipped($order));
特定のキューへの投入
make:mail
コマンドを使用して生成したすべてのMailableクラスはIlluminate\Bus\Queueable
トレイトを利用するため、任意のMailableクラスインスタンスでonQueue
メソッドとonConnection
メソッドを呼び出して、メッセージに使う接続とキュー名を指定できます。
$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);
デフォルトでのキュー投入
常にキューに入れたいMailableクラスがある場合は、クラスにShouldQueue
契約を実装できます。これで、メール送信時にsend
メソッドを呼び出しても、この契約を実装しているため、Mailableはキューへ投入されます。
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderShipped extends Mailable implements ShouldQueue
{
//
}
Mailableのキュー投入とデータベーストランザクション
キュー投入されたMailableがデータベーストランザクション内でディスパッチされると、データベーストランザクションがコミットされる前にキューによって処理される場合があります。これが発生した場合、データベーストランザクション中にモデルまたはデータベースレコードに加えた更新は、データベースにまだ反映されていない可能性があります。さらに、トランザクション内で作成したモデルまたはデータベースレコードは、データベースに存在しない可能性があります。Mailableがこれらのモデルに依存している場合、キューに入れられたMailableを送信するジョブが処理されるときに予期しないエラーが発生する可能性があります。
キュー接続のafter_commit
設定オプションがfalse
に設定されている場合でも、メールメッセージ送信時にafterCommit
メソッドを呼び出せば、キュー投入する特定のMailableが、オープンしているすべてのデータベーストランザクションのコミット後に、ディスパッチすると示せます。
Mail::to($request->user())->send(
(new OrderShipped($order))->afterCommit()
);
あるいは、Mailableのコンストラクタで、afterCommit
メソッドを呼び出すこともできます。
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
/**
* 新しいメッセージインスタンスの生成
*
* @return void
*/
public function __construct()
{
$this->afterCommit();
}
}
Tip!! これらの問題の回避方法の詳細は、キュー投入したジョブとデータベーストランザクションに関するドキュメントを確認してください。
Mailableのレンダ
MailableのHTMLコンテンツを送信せずにキャプチャしたい場合があります。これを行うには、Mailableのrender
メソッドを呼び出してください。このメソッドは、Mailableファイルの評価済みHTMLコンテンツを文字列として返します。
use App\Mail\InvoicePaid;
use App\Models\Invoice;
$invoice = Invoice::find(1);
return (new InvoicePaid($invoice))->render();
ブラウザによるMailableのプレビュー
Mailableのテンプレートを設計するときは、通常のBladeテンプレートのように、レンダ済みMailableをブラウザですばやくプレビューできると便利です。このためLaravelでは、ルートクロージャまたはコントローラから直接Mailableを返せます。Mailableが返されると、ブラウザでレンダされ表示されるため、実際の電子メールアドレスへ送信しなくても、デザインをすばやくプレビューできます。
Route::get('/mailable', function () {
$invoice = App\Models\Invoice::find(1);
return new App\Mail\InvoicePaid($invoice);
});
Note: インライン添付ファイルは、Mailableファイルがブラウザでプレビューされたときにレンダリングされません。これらのメーラブルをプレビューするには、MailHogやHELOなどのメールテストアプリケーションに送信する必要があります。
Mailableの多言語化
Laravelを使用すると、リクエストの現在のロケール以外のロケールでMailableファイルを送信でき、メールがキュー投入される場合でもこのロケールを記憶しています。
これを実現するために、Mail
ファサードは目的の言語を設定するためのlocale
メソッドを提供します。Mailableのテンプレートが評価されると、アプリケーションはこのロケールに変更され、評価が完了すると前のロケールに戻ります。
Mail::to($request->user())->locale('es')->send(
new OrderShipped($order)
);
ユーザー優先ロケール
場合によっては、アプリケーションは各ユーザーの優先ロケールを保存しています。1つ以上のモデルにHasLocalePreference
コントラクトを実装することで、メールを送信するときにこの保存されたロケールを使用するようにLaravelに指示できます。
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* ユーザーの希望するロケールを取得
*
* @return string
*/
public function preferredLocale()
{
return $this->locale;
}
}
このインターフェイスを実装すると、LaravelはMailableと通知をモデルへ送信するとき、自動的に優先ロケールを使用します。したがって、このインターフェイスを使用する場合、locale
メソッドを呼び出す必要はありません。
Mail::to($request->user())->send(new OrderShipped($order));
Mailableのテスト
Laravelでは、Mailableに期待した内容が含まれているかをテストするため、便利なメソッドを提供しています。こうしたメソッドに次のものがあります。assertSeeInHtml
、assertDontSeeInHtml
、assertSeeInOrderInHtml
、assertSeeInText
、assertDontSeeInText
、assertSeeInOrderInText
。
ご想像のとおり、"HTML"アサートは、MailableのHTMLバージョンに特定の文字列が含まれていることを宣言し、"text"アサートは、Mailableの平文テキストバージョンに特定の文字列が含まれていることを宣言します。
use App\Mail\InvoicePaid;
use App\Models\User;
public function test_mailable_content()
{
$user = User::factory()->create();
$mailable = new InvoicePaid($user);
$mailable->assertSeeInHtml($user->email);
$mailable->assertSeeInHtml('Invoice Paid');
$mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);
$mailable->assertSeeInText($user->email);
$mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);
}
Mailableの送信テスト
指定のMailableが特定のユーザーへ「送信」されたことをアサートするテストとは別に、Mailableのコンテンツをテストするのを推奨します。メールが送信されたことをテストする方法については、Mail fakeのドキュメントをご覧ください。
メールとローカル開発
電子メールを送信するアプリケーションを開発する場合、実際の電子メールアドレスに電子メールを送信したくない場合があります。Laravelは、ローカル開発中に実際の電子メールの送信を「無効にする」ためのいくつかの方法を提供します。
Logドライバ
メールを送信する代わりに、log
メールドライバは検査のためにすべてのメールメッセージをログファイルに書き込みます。通常、このドライバはローカル開発中にのみ使用されます。環境ごとのアプリケーションの設定の詳細については、設定ドキュメントを確認してください。
HELO/Mailtrap/MailHog
もしくは、HELOやMailtrapなどのサービスとsmtp
ドライバを使用して、メールメッセージを「ダミー」メールボックスに送信可能です。本当の電子メールクライアントでそれらを表示できます。このアプローチには、Mailtrapのメッセージビューアで最終的な電子メールを実際に調べられるという利点があります。
Laravel Sailを使用している場合は、MailHogを使用してメッセージをプレビューできます。Sailの実行中は、http://localhost:8025
でMailHogインターフェイスにアクセスできます。
グローバルなto
アドレスの使用
最後に、Mail
ファサードが提供するalwaysTo
メソッドを呼び出し、グローバルな「宛先」アドレスを指定する方法です。通常、このメソッドは、アプリケーションのサービスプロバイダのboot
メソッドから呼び出すべきでしょう。
use Illuminate\Support\Facades\Mail;
/**
* アプリケーションの全サービスの初期起動処理
*
* @return void
*/
public function boot()
{
if ($this->app->environment('local')) {
Mail::alwaysTo('taylor@example.com');
}
}
イベント
Laravelは、メールメッセージの送信プロセス中に2つのイベントを発行します。MessageSending
イベントはメッセージが送信される前に発生し、MessageSent
イベントはメッセージが送信された後に発生します。これらのイベントは、メールをキューへ投入したときではなく、メールが送信されているときに発生することを忘れないでください。このイベントのイベントリスナは、App\Providers\EventServiceProvider
サービスプロバイダで登録できます。
/**
* アプリケーションのイベントリスナマッピング
*
* @var array
*/
protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\LogSendingMessage',
],
'Illuminate\Mail\Events\MessageSent' => [
'App\Listeners\LogSentMessage',
],
];
カスタムトランスポート
Laravelは様々なメールトランスポートを用意していますが、Laravelが予めサポートしていない他のサービスを使いメールを配信するため、独自のトランスポートを書きたい場合があり得ます。取り掛かるには、Symfony\Component\Mailer\Transport\AbstractTransport
クラスを継承するクラスを定義します。次に、トランスポートでdoSend
と__toString()
メソッドを実装します。
use MailchimpTransactional\ApiClient;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\MessageConverter;
class MailchimpTransport extends AbstractTransport
{
/**
* Mailchimp APIクライアント
*
* @var \MailchimpTransactional\ApiClient
*/
protected $client;
/**
* 新しいMailchimpトランスポートインスタンスの生成
*
* @param \MailchimpTransactional\ApiClient $client
* @return void
*/
public function __construct(ApiClient $client)
{
$this->client = $client;
}
/**
* {@inheritDoc}
*/
protected function doSend(SentMessage $message): void
{
$email = MessageConverter::toEmail($message->getOriginalMessage());
$this->client->messages->send(['message' => [
'from_email' => $email->getFrom(),
'to' => collect($email->getTo())->map(function ($email) {
return ['email' => $email->getAddress(), 'type' => 'to'];
})->all(),
'subject' => $email->getSubject(),
'text' => $email->getTextBody(),
]]);
}
/**
* トランスポートの文字列表現の取得
*
* @return string
*/
public function __toString(): string
{
return 'mailchimp';
}
}
カスタムトランスポートを定義したら、Mail
ファサードが提供するextend
メソッドで登録します。一般的には、アプリケーションのAppServiceProvider
サービスプロバイダのboot
メソッド内で行います。extend
メソッドへ渡されるクロージャへ、$config
引数が渡されます。この引数には、アプリケーションのconfig/mail.php
設定ファイルで定義してあるメーラーの設定配列が含まれています。
use App\Mail\MailchimpTransport;
use Illuminate\Support\Facades\Mail;
/**
* アプリケーションの全サービスの初期起動処理
*
* @return void
*/
public function boot()
{
Mail::extend('mailchimp', function (array $config = []) {
return new MailchimpTransport(/* ... */);
})
}
カスタムトランスポートを定義し、登録すると、アプリケーションのconfig/mail.php
設定ファイル内に、新しいトランスポートを利用するメーラー定義を作成できます。
'mailchimp' => [
'transport' => 'mailchimp',
// ...
],
Symfonyトランスポートの追加
Laravelは、MailgunやPostmarkのように、Symfonyがメンテナンスしている既存のメールトランスポートをサポートしています。しかし、Laravelを拡張して、Symfonyが保守する追加のトランスポートを追加サポートしたい場合があるでしょう。Composerを使い、必要なSymfonyメーラーをインストールし、Laravelでそのトランスポートを登録することで、これが実現できます。例として、"Sendinblue" Symfonyメーラーをインストールし、登録してみましょう。
composer require symfony/sendinblue-mailer
Sendinblueメーラーパッケージをインストールしたら、アプリケーションのservices
設定ファイルへ、Sendinblue
API認証情報のエントリを追加します。
'sendinblue' => [
'key' => 'your-api-key',
],
最後に、Mail
ファサードのextend
メソッドを使用して、Laravelへこのトランスポートを登録します。一般的に、これはサービスプロバイダのboot
メソッド内で行う必要があります。
use Illuminate\Support\Facades\Mail;
use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
/**
* アプリケーションの全サービスの初期起動処理
*
* @return void
*/
public function boot()
{
Mail::extend('sendinblue', function () {
return (new SendinblueTransportFactory)->create(
new Dsn(
'sendinblue+api',
'default',
config('services.sendinblue.key')
)
);
});
}