- はじめに
- Mailableの生成
- Mailableの作成
- Markdown Mailable
- メールの送信
- Mailableのレンダリング
- Mailableのローカライズ
- テスト
- メールとローカル開発
- イベント
- カスタムトランスポート
#はじめに
メール送信は複雑である必要はありません。Laravelは人気のあるSymfony Mailerコンポーネントをベースにした、シンプルで使いやすいメールAPIを提供します。LaravelとSymfony MailerはSMTP、Mailgun、Postmark、Amazon SES、sendmailを使ったメール送信ドライバーを提供しており、ローカルまたはクラウドベースのサービスを使ってすぐにメール送信を始められます。
#設定
Laravelのメールサービスはアプリケーションのconfig/mail.php設定ファイルで構成します。このファイル内で設定する各メール送信ドライバーは独自の設定や「トランスポート」を持てるため、特定のメール送信に異なるサービスを使い分けられます。例えば、トランザクションメールはPostmarkで送信し、大量メールはAmazon SESで送信することが可能です。
mail設定ファイル内にはmailers設定配列があり、Laravelがサポートする主要なメールドライバー/トランスポートのサンプル設定が含まれています。default設定値は、メール送信時にデフォルトで使用されるメール送信ドライバーを決定します。
#ドライバー/トランスポートの前提条件
Mailgun、Postmark、MailerSendのような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' => [
'transport' => '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のメッセージストリームを指定したい場合は、config/mail.phpの該当ドライバー設定配列にmessage_stream_idオプションを追加できます:
'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'],
],
],
],
#MailerSendドライバー
MailerSendはトランザクションメールとSMSサービスで、Laravel用の独自APIベースのメールドライバーを提供しています。Composerでこのドライバーを含むパッケージをインストールできます:
composer require mailersend/laravel-driver
パッケージをインストールしたら、アプリケーションの.envファイルにMAILERSEND_API_KEY環境変数を追加してください。また、MAIL_MAILER環境変数はmailersendに設定する必要があります:
MAIL_MAILER=mailersend
[email protected]
MAIL_FROM_NAME="App Name"
MAILERSEND_API_KEY=your-api-key
MailerSendの詳細やホステッドテンプレートの使い方については、MailerSendドライバーのドキュメントを参照してください。
#フェイルオーバー設定
外部サービスを使ってメール送信している場合、そのサービスがダウンすることがあります。その際に備えて、プライマリの送信ドライバーが使えない場合に利用するバックアップのメール送信設定を複数定義しておくと便利です。
これを実現するには、アプリケーションのmail設定ファイルにfailoverトランスポートを使うメール送信ドライバーを定義します。failoverドライバーの設定配列には、利用可能なメール送信ドライバーの優先順を示すmailers配列を含めます:
'mailers' => [
'failover' => [
'transport' => 'failover',
'mailers' => [
'postmark',
'mailgun',
'sendmail',
],
],
// ...
],
フェイルオーバードライバーを定義したら、アプリケーションのmail設定ファイルのdefaultキーにこのドライバー名を指定して、デフォルトのメール送信ドライバーとして設定してください:
'default' => env('MAIL_MAILER', 'failover'),
#ラウンドロビン設定
roundrobin トランスポートを使うと、メール送信の負荷を複数のメーラーに分散できます。開始するには、アプリケーションの mail 設定ファイル内で roundrobin トランスポートを使用するメーラーを定義してください。アプリケーションの roundrobin メーラーの設定配列は、配信に使用する設定済みメーラーを参照する mailers 配列を含める必要があります:
'mailers' => [
'roundrobin' => [
'transport' => 'roundrobin',
'mailers' => [
'ses',
'postmark',
],
],
// ...
],
ラウンドロビンドライバーを定義したら、アプリケーションのmail設定ファイルのdefaultキーにこのドライバー名を指定して、デフォルトのメール送信ドライバーとして設定してください:
'default' => env('MAIL_MAILER', 'roundrobin'),
ラウンドロビントランスポートは、設定されたメール送信ドライバーのリストからランダムに1つを選び、次のメール送信ではリストの次のドライバーに切り替えます。failoverトランスポートが*高可用性を実現するのに対し、roundrobinトランスポートは負荷分散*を提供します。
#Mailableの生成
Laravelアプリケーションでは、送信するメールの種類ごとに「mailable」クラスを作成します。これらのクラスはapp/Mailディレクトリに保存されます。まだこのディレクトリがない場合でも心配いりません。make:mail Artisanコマンドで最初のmailableクラスを作成すると自動生成されます。
php artisan make:mail OrderShipped
#Mailableの作成
mailableクラスを生成したら、その中身を見てみましょう。mailableクラスの設定は、envelope、content、attachmentsなどの複数のメソッドで行います。
envelopeメソッドはメッセージの件名や場合によっては受信者を定義するIlluminate\Mail\Mailables\Envelopeオブジェクトを返します。contentメソッドはメッセージ内容を生成するために使うBladeテンプレートを定義するIlluminate\Mail\Mailables\Contentオブジェクトを返します。
#送信者の設定
#Envelopeを使う
まずはメールの送信者、つまりメールの「from」アドレスの設定方法を見てみましょう。送信者の設定は2通りあります。1つ目はメッセージのenvelopeに「from」アドレスを指定する方法です:
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;
/**
* メッセージのenvelopeを取得します。
*/
public function envelope(): Envelope
{
return new Envelope(
from: new Address('[email protected]', 'Jeffrey Way'),
subject: 'Order Shipped',
);
}
必要に応じて、replyToアドレスも指定できます:
return new Envelope(
from: new Address('[email protected]', 'Jeffrey Way'),
replyTo: [
new Address('[email protected]', 'Taylor Otwell'),
],
subject: 'Order Shipped',
);
#グローバルなfromアドレスを使う
もしアプリケーションで全メールに同じ「from」アドレスを使う場合、毎回mailableクラスに追加するのは面倒です。その場合はconfig/mail.php設定ファイルにグローバルな「from」アドレスを指定できます。mailableクラス内で別の「from」アドレスが指定されていなければ、このグローバル設定が使われます:
'from' => [
'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
さらに、config/mail.php 設定ファイル内でグローバルな "reply_to" アドレスを定義できます:
'reply_to' => ['address' => '[email protected]', 'name' => 'App Name'],
#ビューの設定
mailable クラスの content メソッド内で、view を定義できます。これはメールの内容をレンダリングする際に使用するテンプレートを指定します。通常、メールは Bladeテンプレート を使って内容をレンダリングするため、メールのHTMLを作成する際にBladeテンプレートエンジンの強力で便利な機能を活用できます。
/**
* メッセージの内容定義を取得します。
*/
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
);
}
すべてのメールテンプレートをまとめるために resources/views/emails ディレクトリを作成することをおすすめしますが、resources/views 内の好きな場所に配置しても問題ありません。
#プレーンテキストメール
メールのプレーンテキスト版を定義したい場合は、メッセージの Content 定義でプレーンテキスト用テンプレートを指定できます。view パラメータと同様に、text パラメータにはメール内容をレンダリングするテンプレート名を指定します。HTML版とプレーンテキスト版の両方を定義可能です。
/**
* メッセージの内容定義を取得します。
*/
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
text: 'mail.orders.shipped-text'
);
}
わかりやすくするために、html パラメータは view パラメータの別名として使えます。
return new Content(
html: 'mail.orders.shipped',
text: 'mail.orders.shipped-text'
);
#ビューデータ
#パブリックプロパティ経由
通常、メールのHTMLをレンダリングする際に利用するデータをビューに渡したいでしょう。ビューにデータを渡す方法は2つあります。まず、mailable クラスで定義されたパブリックプロパティは自動的にビューで利用可能になります。例えば、mailable クラスのコンストラクタにデータを渡し、そのデータをクラスのパブリックプロパティにセットできます。
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* 新しいメッセージインスタンスを作成します。
*/
public function __construct(
public Order $order,
) {}
/**
* メッセージの内容定義を取得します。
*/
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
);
}
}
データがパブリックプロパティにセットされると、自動的にビューで利用可能になるため、Bladeテンプレート内で他のデータと同様にアクセスできます。
<div>
Price: {{ $order->price }}
</div>
#with パラメータ経由:
メールのデータをテンプレートに渡す前にフォーマットをカスタマイズしたい場合は、Content 定義の with パラメータを使って手動でデータをビューに渡せます。通常は mailable クラスのコンストラクタでデータを渡しますが、その場合はデータを protected または private プロパティにセットし、テンプレートに自動的に渡らないようにします。
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* 新しいメッセージインスタンスを作成します。
*/
public function __construct(
protected Order $order,
) {}
/**
* メッセージの内容定義を取得します。
*/
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
with: [
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
],
);
}
}
with メソッドで渡したデータは自動的にビューで利用可能になるため、Bladeテンプレート内で他のデータと同様にアクセスできます。
<div>
Price: {{ $orderPrice }}
</div>
#添付ファイル
メールに添付ファイルを追加するには、メッセージの attachments メソッドで返す配列に添付ファイルを追加します。まず、Attachment クラスの fromPath メソッドにファイルパスを渡して添付できます。
use Illuminate\Mail\Mailables\Attachment;
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromPath('/path/to/file'),
];
}
ファイルを添付する際、as メソッドや withMime メソッドを使って表示名やMIMEタイプを指定できます。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromPath('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
#ディスクからファイルを添付する
filesystem disks に保存したファイルをメールに添付する場合は、fromStorage 添付メソッドを使えます。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorage('/path/to/file'),
];
}
もちろん、添付ファイルの名前やMIMEタイプも指定可能です。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorage('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
デフォルトのディスク以外を指定したい場合は、fromStorageDisk メソッドを使えます。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromStorageDisk('s3', '/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
#生データの添付
fromData 添付メソッドは、生のバイト列を添付ファイルとして追加できます。例えば、メモリ上で生成したPDFをディスクに書き込まずにメールに添付したい場合に使います。fromData はクロージャを受け取り、生データのバイト列と添付ファイル名を返します。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromData(fn () => $this->pdf, 'Report.pdf')
->withMime('application/pdf'),
];
}
#インライン添付
メールにインライン画像を埋め込むのは通常手間がかかりますが、Laravelは画像をメールに添付する便利な方法を提供します。インライン画像を埋め込むには、メールテンプレート内の $message 変数の embed メソッドを使います。Laravelはすべてのメールテンプレートに $message 変数を自動的に渡すため、手動で渡す必要はありません。
<body>
Here is an image:
<img src="{{ $message->embed($pathToImage) }}">
</body>
プレーンテキストのメッセージテンプレートでは $message 変数は利用できません。プレーンテキストメッセージはインライン添付を使わないためです。
#生データの埋め込み添付
すでに生の画像データ文字列がある場合は、メールテンプレート内の $message 変数の embedData メソッドを呼び出せます。embedData メソッドを呼ぶ際は、埋め込む画像に割り当てるファイル名を指定する必要があります。
<body>
Here is an image from raw data:
<img src="{{ $message->embedData($data, 'example-image.jpg') }}">
</body>
#添付可能なオブジェクト
ファイルパスの文字列で添付するだけで十分な場合もありますが、多くの場合、アプリケーション内の添付対象はクラスで表現されます。例えば、写真をメッセージに添付する場合、その写真を表す Photo モデルがあるかもしれません。その場合、Photo モデルを attach メソッドに渡せたら便利です。添付可能なオブジェクトはそれを可能にします。
まず、メッセージに添付可能なオブジェクトとして使いたいクラスに 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
{
/**
* モデルの添付可能な表現を取得します。
*/
public function toMailAttachment(): Attachment
{
return Attachment::fromPath('/path/to/file');
}
}
添付可能なオブジェクトを定義したら、メールメッセージを作成する際の attachments メソッドでそのオブジェクトのインスタンスを返せます。
/**
* メッセージの添付ファイルを取得します。
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [$this->photo];
}
もちろん、添付データはAmazon S3のようなリモートファイルストレージに保存されている場合もあります。そのため、Laravelはアプリケーションの filesystem disks に保存されたデータから添付インスタンスを生成することも可能です。
// デフォルトディスク上のファイルから添付を作成...
return Attachment::fromStorage($this->path);
// 特定のディスク上のファイルから添付を作成...
return Attachment::fromStorageDisk('backblaze', $this->path);
さらに、メモリ上のデータから添付インスタンスを作成できます。これを実現するには、fromData メソッドにクロージャを渡し、そのクロージャが添付を表す生データを返すようにします。
return Attachment::fromData(fn () => $this->content, 'Photo Name');
Laravelは添付ファイルをカスタマイズするための追加メソッドも提供しています。例えば、as と withMime メソッドを使ってファイル名やMIMEタイプをカスタマイズできます。
return Attachment::fromPath('/path/to/file')
->as('Photo Name')
->withMime('image/jpeg');
#ヘッダー
送信メッセージに追加のヘッダーを付けたい場合があります。例えば、カスタムの Message-Id やその他任意のテキストヘッダーを設定したい場合です。
これを実現するには、mailable に headers メソッドを定義します。headers メソッドは Illuminate\Mail\Mailables\Headers インスタンスを返す必要があります。このクラスは messageId、references、text パラメータを受け取ります。もちろん、必要なパラメータだけを指定できます。
use Illuminate\Mail\Mailables\Headers;
/**
* メッセージヘッダーを取得します。
*/
public function headers(): Headers
{
return new Headers(
messageId: '[email protected]',
references: ['[email protected]'],
text: [
'X-Custom-Header' => 'Custom Value',
],
);
}
#タグとメタデータ
Mailgun や Postmark などのサードパーティのメールプロバイダーは、メッセージの「タグ」や「メタデータ」をサポートしており、これらを使ってアプリケーションから送信したメールをグループ化・追跡できます。メールメッセージにタグやメタデータを追加するには、Envelope 定義で指定します:
use Illuminate\Mail\Mailables\Envelope;
/**
* メッセージのエンベロープを取得します。
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Order Shipped',
tags: ['shipment'],
metadata: [
'order_id' => $this->order->id,
],
);
}
Mailgun ドライバーを使用している場合は、タグやメタデータに関する詳細は Mailgun のドキュメントを参照してください。同様に、Postmark のドキュメントもタグやメタデータのサポートについて確認できます。
Amazon SES を使ってメールを送信する場合は、メッセージに SES のタグを添付するために metadata メソッドを使用してください。
#Symfony メッセージのカスタマイズ
Laravel のメール機能は Symfony Mailer によって実現されています。Laravel では、メッセージ送信前に Symfony の Message インスタンスを受け取るカスタムコールバックを登録できます。これにより、送信前にメッセージを詳細にカスタマイズできます。これを行うには、Envelope 定義に using パラメータを指定します:
use Illuminate\Mail\Mailables\Envelope;
use Symfony\Component\Mime\Email;
/**
* メッセージのエンベロープを取得します。
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Order Shipped',
using: [
function (Email $message) {
// ...
},
]
);
}
#Markdown メーラブル
Markdown メーラブルメッセージは、メール通知の事前構築されたテンプレートやコンポーネントを活用できます。メッセージが Markdown で記述されているため、Laravel は美しくレスポンシブな HTML テンプレートをレンダリングしつつ、プレーンテキストの代替も自動生成します。
#Markdown メーラブルの生成
対応する Markdown テンプレート付きのメーラブルを生成するには、make:mail Artisan コマンドの --markdown オプションを使用します:
php artisan make:mail OrderShipped --markdown=mail.orders.shipped
その後、メーラブルの content メソッド内で Content 定義を設定する際に、view パラメータの代わりに markdown パラメータを使います:
use Illuminate\Mail\Mailables\Content;
/**
* メッセージのコンテンツ定義を取得します。
*/
public function content(): Content
{
return new Content(
markdown: 'mail.orders.shipped',
with: [
'url' => $this->orderUrl,
],
);
}
#Markdown メッセージの記述
Markdown メーラブルは Blade コンポーネントと Markdown 構文を組み合わせて使い、Laravel の事前構築されたメール UI コンポーネントを活用しながら簡単にメールメッセージを構築できます:
<x-mail::message>
# Order Shipped
Your order has been shipped!
<x-mail::button :url="$url">
View Order
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
Markdown メールを書く際は過剰なインデントを避けてください。Markdown の仕様により、インデントされた内容はコードブロックとして解釈されます。
#ボタンコンポーネント
ボタンコンポーネントは中央揃えのボタンリンクをレンダリングします。url とオプションの color の2つの引数を受け付けます。サポートされている色は primary、success、error です。メッセージに複数のボタンコンポーネントを追加できます:
<x-mail::button :url="$url" color="success">
View Order
</x-mail::button>
#パネルコンポーネント
パネルコンポーネントは、メッセージの他の部分とは異なる背景色のパネル内にテキストブロックを表示します。これにより、特定のテキストに注目を集められます:
<x-mail::panel>
This is the panel content.
</x-mail::panel>
#テーブルコンポーネント
テーブルコンポーネントは Markdown テーブルを HTML テーブルに変換します。Markdown テーブルをコンテンツとして受け取り、Markdown の標準的なテーブル列の配置指定もサポートします:
<x-mail::table>
| Laravel | Table | Example |
| ------------- |:-------------:| --------:|
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
</x-mail::table>
#コンポーネントのカスタマイズ
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 コンポーネント用にまったく新しいテーマを作成したい場合は、html/themes ディレクトリに CSS ファイルを配置してください。ファイル名を付けて保存したら、アプリケーションの config/mail.php 設定ファイルの theme オプションを新しいテーマ名に更新します。
個別のメーラブルでテーマをカスタマイズしたい場合は、メーラブルクラスの $theme プロパティに使用するテーマ名を設定してください。
#メールの送信
メッセージを送信するには、Mail ファサードの to メソッドを使います。to メソッドはメールアドレス、ユーザーインスタンス、またはユーザーのコレクションを受け付けます。オブジェクトやコレクションを渡すと、メール送信時に自動的にそれらの email と name プロパティが使われるため、これらの属性が利用可能であることを確認してください。受信者を指定したら、メーラブルクラスのインスタンスを send メソッドに渡して送信します:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Mail\OrderShipped;
use App\Models\Order;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class OrderShipmentController extends Controller
{
/**
* 指定された注文を発送します。
*/
public function store(Request $request): RedirectResponse
{
$order = Order::findOrFail($request->order_id);
// 注文を発送する...
Mail::to($request->user())->send(new OrderShipped($order));
return redirect('/orders');
}
}
メッセージ送信時に「to」受信者だけでなく、「cc」や「bcc」もそれぞれのメソッドをチェーンして設定できます:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
#受信者のループ処理
配列の受信者やメールアドレスに対してメーラブルを送信する場合があります。ただし、to メソッドは受信者リストにメールアドレスを追加するため、ループの各回で前の受信者にもメールが送信されてしまいます。したがって、受信者ごとにメーラブルインスタンスを再作成してください:
foreach (['[email protected]', '[email protected]'] 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 コマンドで生成されたメーラブルクラスはすべて Illuminate\Bus\Queueable トレイトを使っているため、任意のメーラブルインスタンスで onQueue と onConnection メソッドを呼び出せます。これにより、接続名やキュー名を指定できます:
$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);
#デフォルトでキューイング
常にキューイングしたいメーラブルクラスには、ShouldQueue インターフェイスを実装してください。これにより、send メソッドを呼んでもメーラブルはキューに入ります:
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderShipped extends Mailable implements ShouldQueue
{
// ...
}
#キューイングされたメーラブルとデータベーストランザクション
キューイングされたメーラブルがデータベーストランザクション内でディスパッチされると、トランザクションがコミットされる前にキューで処理される可能性があります。この場合、トランザクション中に行ったモデルやデータベースレコードの更新がまだ反映されていなかったり、トランザクション内で作成されたモデルやレコードが存在しないことがあります。メーラブルがこれらのモデルに依存していると、ジョブ処理時に予期しないエラーが発生する可能性があります。
キュー接続の after_commit 設定が false の場合でも、特定のキューイングされたメーラブルをすべてのオープントランザクションがコミットされた後にディスパッチするには、メール送信時に afterCommit メソッドを呼び出してください:
Mail::to($request->user())->send(
(new OrderShipped($order))->afterCommit()
);
または、メーラブルのコンストラクタ内で 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;
/**
* 新しいメッセージインスタンスを作成します。
*/
public function __construct()
{
$this->afterCommit();
}
}
これらの問題を回避する方法については、キュージョブとデータベーストランザクションのドキュメントをご覧ください。
#Mailables のレンダリング
メールを送信せずに mailable の HTML コンテンツを取得したい場合があります。その場合は、mailable の render メソッドを呼び出します。このメソッドは、mailable の評価済み HTML コンテンツを文字列として返します。
use App\Mail\InvoicePaid;
use App\Models\Invoice;
$invoice = Invoice::find(1);
return (new InvoicePaid($invoice))->render();
#ブラウザでの Mailables プレビュー
mailable のテンプレートを設計する際、通常の Blade テンプレートのようにブラウザで素早くレンダリング結果をプレビューできると便利です。そのため、Laravel ではルートクロージャやコントローラーから直接 mailable を返すことができます。mailable を返すとブラウザにレンダリング結果が表示され、実際にメールを送信せずにデザインを確認できます。
Route::get('/mailable', function () {
$invoice = App\Models\Invoice::find(1);
return new App\Mail\InvoicePaid($invoice);
});
#Mailables のローカライズ
Laravel では、リクエストの現在のロケールとは異なるロケールで mailables を送信でき、キューに入れた場合でもそのロケールを保持します。
これを実現するために、Mail ファサードは希望する言語を設定する locale メソッドを提供します。mailable のテンプレート評価時にアプリケーションはこのロケールに切り替わり、評価完了後に元のロケールに戻ります。
Mail::to($request->user())->locale('es')->send(
new OrderShipped($order)
);
#ユーザーの優先ロケール
アプリケーションによっては、ユーザーごとに優先ロケールを保存している場合があります。モデルに HasLocalePreference インターフェイスを実装することで、Laravel はメール送信時にこの保存されたロケールを使用します。
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* ユーザーの優先ロケールを取得します。
*/
public function preferredLocale(): string
{
return $this->locale;
}
}
インターフェイスを実装すると、Laravel は自動的に mailables や通知の送信時に優先ロケールを使用するため、locale メソッドを呼ぶ必要はありません。
Mail::to($request->user())->send(new OrderShipped($order));
#テスト
#Mailable の内容テスト
Laravel は mailable の構造を検査するためのさまざまなメソッドを提供します。さらに、mailable に期待する内容が含まれているかをテストする便利なメソッドも用意されています。これらは assertSeeInHtml、assertDontSeeInHtml、assertSeeInOrderInHtml、assertSeeInText、assertDontSeeInText、assertSeeInOrderInText、assertHasAttachment、assertHasAttachedData、assertHasAttachmentFromStorage、assertHasAttachmentFromStorageDisk です。
ご想像の通り、「HTML」系のアサーションは mailable の HTML バージョンに指定した文字列が含まれていることを確認し、「text」系のアサーションはプレーンテキストバージョンに指定した文字列が含まれていることを確認します。
use App\Mail\InvoicePaid;
use App\Models\User;
public function test_mailable_content(): void
{
$user = User::factory()->create();
$mailable = new InvoicePaid($user);
$mailable->assertFrom('[email protected]');
$mailable->assertTo('[email protected]');
$mailable->assertHasCc('[email protected]');
$mailable->assertHasBcc('[email protected]');
$mailable->assertHasReplyTo('[email protected]');
$mailable->assertHasSubject('Invoice Paid');
$mailable->assertHasTag('example-tag');
$mailable->assertHasMetadata('key', 'value');
$mailable->assertSeeInHtml($user->email);
$mailable->assertSeeInHtml('Invoice Paid');
$mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);
$mailable->assertSeeInText($user->email);
$mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);
$mailable->assertHasAttachment('/path/to/file');
$mailable->assertHasAttachment(Attachment::fromPath('/path/to/file'));
$mailable->assertHasAttachedData($pdfData, 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorage('/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
$mailable->assertHasAttachmentFromStorageDisk('s3', '/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);
}
#Mailable の送信テスト
mailable の内容テストは、特定のユーザーに「送信された」ことを確認するテストとは別に行うことを推奨します。通常、mailable の内容はテスト対象のコードに関係ないため、Laravel が指定した mailable を送信するよう指示したことを確認するだけで十分です。
Mail ファサードの fake メソッドを使用してメールが送信されるのを防げます。Mail ファサードの fake メソッドを呼び出した後、Mailable がユーザーに送信されるよう指示されたことをアサートしたり、Mailable が受け取ったデータを検査したりできます:
<?php
namespace Tests\Feature;
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped(): void
{
Mail::fake();
// 注文の発送処理を実行...
// メールが一通も送信されていないことを確認...
Mail::assertNothingSent();
// mailable が送信されたことを確認...
Mail::assertSent(OrderShipped::class);
// mailable が2回送信されたことを確認...
Mail::assertSent(OrderShipped::class, 2);
// mailable が送信されていないことを確認...
Mail::assertNotSent(AnotherMailable::class);
// 合計3通の mailable が送信されたことを確認...
Mail::assertSentCount(3);
}
}
バックグラウンドで mailables をキューイングしている場合は、assertSent の代わりに assertQueued メソッドを使うべきです。
Mail::assertQueued(OrderShipped::class);
Mail::assertNotQueued(OrderShipped::class);
Mail::assertNothingQueued();
Mail::assertQueuedCount(3);
assertSent、assertNotSent、assertQueued、assertNotQueued メソッドにはクロージャを渡せます。これにより、指定した「真偽テスト」を通過する mailable が送信されたかをアサートできます。条件を満たす mailable が1つでもあればアサーションは成功します。
Mail::assertSent(function (OrderShipped $mail) use ($order) {
return $mail->order->id === $order->id;
});
Mail ファサードのアサーションメソッドに渡すクロージャで受け取る mailable インスタンスは、mailable を検査するための便利なメソッドを提供します。
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) {
return $mail->hasTo($user->email) &&
$mail->hasCc('...') &&
$mail->hasBcc('...') &&
$mail->hasReplyTo('...') &&
$mail->hasFrom('...') &&
$mail->hasSubject('...');
});
mailable インスタンスは添付ファイルを検査するための便利なメソッドも含みます。
use Illuminate\Mail\Mailables\Attachment;
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
return $mail->hasAttachment(
Attachment::fromPath('/path/to/file')
->as('name.pdf')
->withMime('application/pdf')
);
});
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
return $mail->hasAttachment(
Attachment::fromStorageDisk('s3', '/path/to/file')
);
});
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($pdfData) {
return $mail->hasAttachment(
Attachment::fromData(fn () => $pdfData, 'name.pdf')
);
});
メールが送信されていないことをアサートするメソッドは assertNotSent と assertNotQueued の2種類があります。メールが送信もキューもされていないことを確認したい場合は、assertNothingOutgoing と assertNotOutgoing を使います。
Mail::assertNothingOutgoing();
Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) {
return $mail->order->id === $order->id;
});
#メールとローカル開発
メール送信機能を持つアプリケーションを開発する際、実際のメールアドレスにメールを送信したくないことが多いです。Laravel はローカル開発中にメール送信を「無効化」するいくつかの方法を提供します。
#ログドライバー
メールを送信する代わりに、log メールドライバーはすべてのメールメッセージをログファイルに書き込みます。通常、このドライバーはローカル開発時のみ使用します。環境ごとの設定方法については設定ドキュメントを参照してください。
#HELO / Mailtrap / Mailpit
または、HELO や Mailtrap のようなサービスと smtp ドライバーを使い、メールを「ダミー」メールボックスに送信して実際のメールクライアントで閲覧できます。この方法は Mailtrap のメッセージビューアで最終メールを確認できる利点があります。
Laravel Sail を使っている場合は、Mailpit でメッセージをプレビューできます。Sail 実行中は http://localhost:8025 で Mailpit インターフェースにアクセス可能です。
#グローバルな to アドレスの使用
最後に、Mail ファサードの alwaysTo メソッドを呼び出すことでグローバルな「to」アドレスを指定できます。通常、このメソッドはアプリケーションのサービスプロバイダーの boot メソッド内で呼び出します。
use Illuminate\Support\Facades\Mail;
/**
* アプリケーションサービスのブートストラップ処理。
*/
public function boot(): void
{
if ($this->app->environment('local')) {
Mail::alwaysTo('[email protected]');
}
}
#イベント
Laravel はメール送信処理中に2つのイベントを発火します。MessageSending イベントはメール送信前に、MessageSent イベントは送信後に発火します。これらのイベントはメールが 送信されるとき に発火し、キューに入れられたときではありません。App\Providers\EventServiceProvider でこれらのイベントリスナーを登録できます。
use App\Listeners\LogSendingMessage;
use App\Listeners\LogSentMessage;
use Illuminate\Mail\Events\MessageSending;
use Illuminate\Mail\Events\MessageSent;
/**
* アプリケーションのイベントリスナーのマッピング。
*
* @var array
*/
protected $listen = [
MessageSending::class => [
LogSendingMessage::class,
],
MessageSent::class => [
LogSentMessage::class,
],
];
#カスタムトランスポート
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\Address;
use Symfony\Component\Mime\MessageConverter;
class MailchimpTransport extends AbstractTransport
{
/**
* 新しい Mailchimp トランスポートインスタンスを作成します。
*/
public function __construct(
protected ApiClient $client,
) {
parent::__construct();
}
/**
* {@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 (Address $email) {
return ['email' => $email->getAddress(), 'type' => 'to'];
})->all(),
'subject' => $email->getSubject(),
'text' => $email->getTextBody(),
]]);
}
/**
* トランスポートの文字列表現を取得します。
*/
public function __toString(): string
{
return 'mailchimp';
}
}
カスタムトランスポートを定義したら、Mail ファサードの extend メソッドを使って登録できます。通常はアプリケーションの AppServiceProvider サービスプロバイダーの boot メソッド内で行います。extend メソッドに渡すクロージャには $config 引数が渡され、これはアプリケーションの config/mail.php 設定ファイルで定義されたメール設定の配列を含みます。
use App\Mail\MailchimpTransport;
use Illuminate\Support\Facades\Mail;
/**
* アプリケーションサービスをブートストラップします。
*/
public function boot(): void
{
Mail::extend('mailchimp', function (array $config = []) {
return new MailchimpTransport(/* ... */);
});
}
カスタムトランスポートを定義し登録したら、アプリケーションの config/mail.php 設定ファイル内で新しいトランスポートを利用するメール定義を作成できます。
'mailchimp' => [
'transport' => 'mailchimp',
// ...
],
#追加の Symfony トランスポート
Laravel は Mailgun や Postmark などの既存の Symfony 管理トランスポートをサポートしていますが、さらに他の Symfony 管理トランスポートを追加したい場合があります。必要な Symfony メーラーを Composer でインストールし、Laravel にトランスポートを登録することで対応できます。例えば、「Brevo」(旧 Sendinblue) Symfony メーラーをインストールして登録する方法があります。
composer require symfony/brevo-mailer symfony/http-client
Brevo メーラーパッケージをインストールしたら、アプリケーションの services 設定ファイルに Brevo API 認証情報のエントリを追加します。
'brevo' => [
'key' => 'your-api-key',
],
次に、Mail ファサードの extend メソッドを使って Laravel にトランスポートを登録します。通常はサービスプロバイダーの boot メソッド内で行います。
use Illuminate\Support\Facades\Mail;
use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
/**
* アプリケーションサービスをブートストラップします。
*/
public function boot(): void
{
Mail::extend('brevo', function () {
return (new BrevoTransportFactory)->create(
new Dsn(
'brevo+api',
'default',
config('services.brevo.key')
)
);
});
}
トランスポートを登録したら、アプリケーションの config/mail.php 設定ファイル内で新しいトランスポートを利用する mailer 定義を作成できます:
'brevo' => [
'transport' => 'brevo',
// ...
],