イントロダクション
メール送信を複雑にする必要はありません。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クラスを生成したら、その中身を調べるために開いてみましょう。Mailableクラスの設定は、envelope
、content
、attachments
などのメソッドで行います。
envelope
メソッドは、メッセージのサブジェクトと、時折り受信者を定義する、Illuminate\Mail\Mailables\Envelope
オブジェクトを返します。content
メソッドは、メッセージの内容を生成するために使用するBladeテンプレートを定義する、Illuminate\Mail\Mailables\Content
オブジェクトを返します。
Senderの設定
Envelopeの使用
まず、メール送信者の設定を調べてみましょう。つまり、「誰から送られた」メールかということです。送信者の設定は、2つの方法があります。まず、メッセージのEnvelope(封筒)に"from"アドレスを指定する方法です。
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;
/**
* メッセージEnvelopeを取得
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
from: new Address('jeffrey@example.com', 'Jeffrey Way'),
subject: 'Order Shipped',
);
}
お望みであれば、replyTo
アドレスも指定できます。
return new Envelope(
from: new Address('jeffrey@example.com', 'Jeffrey Way'),
replyTo: [
new Address('taylor@example.com', 'Taylor Otwell'),
],
subject: 'Order 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クラスのcontent
メソッド内でview
、つまりメールのコンテンツをレンダリングするときどのテンプレートを使用するかを定義します。各メールは通常、Bladeテンプレートを使用してコンテンツをレンダするので、メールのHTML構築にBladeテンプレート・エンジンのパワーと利便性をフル活用できます。
/**
* メッセージ内容の定義を取得
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
);
}
Note: すべてのメールテンプレートを格納するために
resources/views/emails
ディレクトリを作成することを推奨します。ただし、resources/views
ディレクトリ内ならば好きな場所へ自由に配置できます。
平文テキストの電子メール
平文テキスト版のメールを定義したい場合は、メッセージのContent
定義を作成するときに、平文テキストのテンプレートを指定してください。view
パラメータと同様、text
パラメータにはメールの内容をレンダするために使用するテンプレートの名前を指定します。HTMLバージョンと平文テキストバージョンの両方を自由に定義できます。
/**
* メッセージ内容の定義を取得
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);
}
明確にするために、html
パラメータをview
パラメータの別名として使用できます。
return new Content(
html: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);
ビューデータ
Publicなプロパティ経由
通常、電子メールの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;
/**
* 注文インスタンス
*
* @var \App\Models\Order
*/
public $order;
/**
* 新しいメッセージインスタンスの生成
*
* @param \App\Models\Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* メッセージ内容の定義を取得
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
);
}
}
データをパブリックプロパティへ設定すると、ビューで自動的に利用できるようになるため、Bladeテンプレートの他のデータにアクセスするのと同じようにアクセスできます。
<div>
Price: {{ $order->price }}
</div>
with
パラメータ経由
もし、テンプレートへ送る前にメールのデータフォーマットをカスタマイズしたい場合は、Content
定義のwith
パラメータを使用して、手作業でデータをビューに渡すこともできます。しかし、このデータを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;
/**
* 注文インスタンス
*
* @var \App\Models\Order
*/
protected $order;
/**
* 新しいメッセージインスタンスの生成
*
* @param \App\Models\Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* メッセージ内容の定義を取得
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.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 \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
return [
Attachment::fromPath('/path/to/file'),
];
}
メッセージへファイルを添付するときに、as
とwithMime
メソッドを使い、添付ファイルの表示名とMIMEタイプを指定することもできます。
/**
* メッセージの添付を取得
*
* @return \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
return [
Attachment::fromPath('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
ディスクからファイルを添付
ファイルシステムディスクのいずれかにファイルを保存している場合、fromStorage
添付メソッドを使用してメールへ添付できます。
/**
* メッセージの添付を取得
*
* @return \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
return [
Attachment::fromStorage('/path/to/file'),
];
}
もちろん、添付ファイル名とMIMEタイプも指定できます。
/**
* メッセージの添付を取得
*
* @return \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
return [
Attachment::fromStorage('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
デフォルトディスク以外のストレージディスクを指定する必要がある場合は、fromStorageDisk
メソッドを使用してください。
/**
* メッセージの添付を取得
*
* @return \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
return [
Attachment::fromStorageDisk('s3', '/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
素のデータの添付ファイル
fromData
添付メソッドを使用すると、生のバイト列を添付ファイルにできます。例えば、メモリ上でPDFを生成し、それをディスクへ一旦書き込まずにメールへ添付したい場合は、このメソッドを使用します。fromData
メソッドは、添付ファイルに割り当てるべき名前と同時に、生のデータバイトを解決するクロージャを受け取ります。
/**
* メッセージの添付を取得
*
* @return \Illuminate\Mail\Mailables\Attachment[]
*/
public function attachments()
{
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>
Warning!! 平文ンテキストメッセージはインライン添付ファイルを利用しないため、
$message
変数は平文テキストメッセージテンプレートでは使用できません。
素のデータの添付ファイルへの埋め込み
電子メールテンプレートに埋め込みたい素の画像データ文字列がすでにある場合は、$message
変数でembedData
メソッドを呼び出すことができます。embedData
メソッドを呼び出すときは、埋め込み画像に割り当てる必要のあるファイル名を指定する必要があります。
<body>
Here is an image from raw data:
<img src="{{ $message->embedData($data, 'example-image.jpg') }}">
</body>
Attachableオブジェクト
単純な文字列のパスを介してメッセージへファイルを添付すれば十分なことがある一方で、多くの場合、アプリケーション内の添付可能(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
{
/**
* モデルの添付可能な形式を取得
*
* @return \Illuminate\Mail\Attachment
*/
public function toMailAttachment()
{
return Attachment::fromPath('/path/to/file');
}
}
添付可能なオブジェクトを定義したら、メールメッセージを作成する際にattachments
メソッドにより、そのオブジェクトのインスタンスを返してください。
/**
* メッセージの添付の取得
*
* @return array
*/
public function attachments()
{
return [$this->photo];
}
もちろん、添付ファイルデータは、Amazon S3などのリモートファイルストレージサービスに保存されている場合もあるでしょう。そのため、Laravelでは、アプリケーションのファイルシステム・ディスクのいずれかに保存しているデータから、添付ファイルのインスタンスを生成することも可能です。
// デフォルトデスクから、添付ファイルを作成する
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;
/**
* メッセージヘッダの取得
*
* @return \Illuminate\Mail\Mailables\Headers
*/
public function headers()
{
return new Headers(
messageId: 'custom-message-id@example.com',
references: ['previous-message@example.com'],
text: [
'X-Custom-Header' => 'Custom Value',
],
);
}
タグとメタデータ
MailgunやPostmarkなどのサードパーティのメールプロバイダーは、メッセージの「タグ」や「メタデータ」をサポートしており、アプリケーションが送信したメールをグループ化し、追跡しするために使用できます。タグやメタデータは、Envelope
定義により、メールメッセージへ追加します。
use Illuminate\Mail\Mailables\Envelope;
/**
* メッセージEnvelopeの取得
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
subject: 'Order Shipped',
tags: ['shipment'],
metadata: [
'order_id' => $this->order->id,
],
);
}
アプリケーションでMailgunドライバを使用している場合、タグとメタデータの詳細は、Mailgunのドキュメントを参照してください。同様に、Postmarkのドキュメントも、タグとメタデータのサポートについて、詳しい情報を得るために参照できます。
アプリケーションがAmazon
SESを使用してメールを送信している場合、metadata
メソッドを使用して、メッセージへSES
「タグ」を添付する必要があります。
Symfonyメッセージのカスタマイズ
Laravelのメール機能は、Symfony
Mailerによって提供されています。Laravelでは、メッセージを送信する前に、Symfonyのメッセージインスタンスで呼び出されるカスタムコールバックを登録できます。これにより、メッセージ送信前に、そのメッセージを深くカスタマイズするチャンスが得られます。これを利用するには、Envelope
定義でusing
パラメータを定義します。
use Illuminate\Mail\Mailables\Envelope;
use Symfony\Component\Mime\Email;
/**
* メッセージEnvelopeの取得
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
subject: 'Order Shipped',
using: [
function (Email $message) {
// ...
},
]
);
}
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のContent
定義をそのcontent
メソッド内で設定するときに、view
パラメータの代わりに、markdown
パラメータを使用します。
use Illuminate\Mail\Mailables\Content;
/**
* メッセージ内容の定義を取得
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
markdown: 'emails.orders.shipped',
with: [
'url' => $this->orderUrl,
],
);
}
Markdownメッセージの記述
Markdown Mailableは、BladeコンポーネントとMarkdown構文の組み合わせを使用して、Laravelに組み込まれた電子メールUIコンポーネントを活用しながら、メールメッセージを簡単に作成できるようにします。
<x-mail::message>
# 発送
注文を発送しました。
<x-mail::button :url="$url">
注文の確認
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
Note: Markdownメールを書くときに余分なインデントを使用しないでください。Markdown標準に従って、Markdownパーサーはインデントされたコンテンツをコードブロックとしてレンダリングします。
ボタンコンポーネント
ボタンコンポーネントは、中央に配置されたボタンリンクをレンダします。コンポーネントは、url
とオプションのcolor
の2つの引数を取ります。サポートしている色は、primary
、success
、error
です。メッセージには、必要なだけのボタンコンポーネントを追加できます。
<x-mail::button :url="$url" color="success">
注文の確認
</x-mail::button>
パネルコンポーネント
パネルコンポーネントは、メッセージの残りの部分とはわずかに異なる背景色を持つパネルで、指定するテキストのブロックをレンダします。これにより、特定のテキストブロックに注意を引くことができます。
<x-mail::panel>
ここはパネルの本文。
</x-mail::panel>
テーブルコンポーネント
テーブルコンポーネントを使用すると、MarkdownテーブルをHTMLテーブルに変換できます。コンポーネントは、そのコンテンツとしてMarkdownテーブルを受け入れます。テーブルの列の配置は、デフォルトのMarkdownテーブルの配置構文をサポートします。
<x-mail::table>
| Laravel | テーブル | 例 |
| ------------- |:-------------:| --------:|
| 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コンポーネント用にまったく新しいテーマを作成したい場合は、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();
}
}
Note: これらの問題の回避方法の詳細は、キュー投入したジョブとデータベーストランザクションに関するドキュメントを確認してください。
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);
});
Warning!! インライン添付ファイルは、Mailableファイルがブラウザでプレビューされたときにレンダリングされません。これらのメーラブルをプレビューするには、Mailpitや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の構造を調べる数多くのメソッドを提供しています。さらに、期待するコンテンツがMailableに含まれているかをテストするために便利なメソッドをいくらか用意しています。これらのメソッドは以下の通りです。assertSeeInHtml
、assertDontSeeInHtml
、assertSeeInOrderInHtml
、assertSeeInText
、assertDontSeeInText
、assertSeeInOrderInText
、assertHasAttachment
、assertHasAttachedData
、assertHasAttachmentFromStorage
、assertHasAttachmentFromStorageDisk
ご想像のとおり、"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->assertFrom('jeffrey@example.com');
$mailable->assertTo('taylor@example.com');
$mailable->assertHasCc('abigail@example.com');
$mailable->assertHasBcc('victoria@example.com');
$mailable->assertHasReplyTo('tyler@example.com');
$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のコンテンツをテストするのを推奨します。メールが送信されたことをテストする方法については、Mail fakeのドキュメントをご覧ください。
メールとローカル開発
電子メールを送信するアプリケーションを開発する場合、実際の電子メールアドレスに電子メールを送信したくない場合があります。Laravelは、ローカル開発中に実際の電子メールの送信を「無効にする」ためのいくつかの方法を提供します。
Logドライバ
メールを送信する代わりに、log
メールドライバは検査のためにすべてのメールメッセージをログファイルに書き込みます。通常、このドライバはローカル開発中にのみ使用されます。環境ごとのアプリケーションの設定の詳細については、設定ドキュメントを確認してください。
HELO/Mailtrap/Mailpit
もしくは、HELOやMailtrapなどのサービスとsmtp
ドライバを使用して、メールメッセージを「ダミー」メールボックスに送信可能です。本当の電子メールクライアントでそれらを表示できます。このアプローチには、Mailtrapのメッセージビューアで最終的な電子メールを実際に調べられるという利点があります。
Laravel Sailを使用している場合は、Mailpitを使用してメッセージをプレビューできます。Sailの実行中は、http://localhost:8025
でMailpitインターフェイスにアクセスできます。
グローバルな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
サービスプロバイダで登録できます。
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\MessageConverter;
class MailchimpTransport extends AbstractTransport
{
/**
* Mailchimp APIクライアント
*
* @var \MailchimpTransactional\ApiClient
*/
protected $client;
/**
* 新しいMailchimpトランスポートインスタンスの生成
*
* @param \MailchimpTransactional\ApiClient $client
* @return void
*/
public function __construct(ApiClient $client)
{
parent::__construct();
$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 symfony/http-client
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')
)
);
});
}
トランスポートを登録したら、アプリケーションのconfig/mail.php
設定ファイル内に、その新しいトランスポートを利用するメーラー定義を作成します。
'sendinblue' => [
'transport' => 'sendinblue',
// ...
],