本文へ移動
Laravel Tips

メールを送る

Laravel でメールを送る方法を、送信サービスの設定・メールのクラス(メイラブル)の書き方・添付・キュー・テスト・手元での確かめ方まで説明します。

Laravel では、メールを簡単に送れます。送るための道具は、Symfony Mailer という有名な部品が支えています。SMTP(メールを送る昔からの決まり)・Cloudflare・Mailgun・Postmark・Resend・Amazon SES・sendmail など、いろいろな送り方(ドライバー)に対応しているので、自分に合ったサービスを選べます。

Laravel では、アプリが送るメール1種類ごとに、メイラブル(mailable)という1つのクラスを作ります。注文が発送されたときのメール、請求書のメール、のように分けて書きます。

設定#

メールの設定は、config/mail.php に書きます。この中の「メイラー」(mailer)ごとに、別々の設定と、別々の送り方(トランスポート)を決められます。たとえば、注文の確認のような大事なメールは Postmark で、大量に送るメールは Amazon SES で、と使い分けられます。

mail 設定の mailers の配列には、Laravel が対応する主な送り方の見本が入っています。default は、アプリがメールを送るとき、ふつうに使うメイラーを決めます。

送り方ごとの準備#

Mailgun・Postmark・Resend のように、API(ほかのプログラムから使う窓口)を使う送り方は、SMTP のサーバーで送るより、簡単で速いことが多いです。できるだけ、API を使う送り方をおすすめします。

Cloudflare#

Symfony の HTTP クライアント(ほかのサーバーへ HTTP で問い合わせる部品)を、Composer(PHP の部品を入れる道具)で入れます。

bash
composer require symfony/http-client

次に、config/mail.php を2か所変えます。まず、既定のメイラーを cloudflare にします。

php
'default' => env('MAIL_MAILER', 'cloudflare'),

次に、mailers の配列に、次の設定を足します。

php
'cloudflare' => [
    'transport' => 'cloudflare',
],

既定のメイラーを決めたら、config/services.php に、次の設定を足します。

php
'cloudflare' => [
    'account_id' => env('CLOUDFLARE_ACCOUNT_ID'),
    'key' => env('CLOUDFLARE_KEY'),
],

Mailgun#

Symfony の Mailgun Mailer のトランスポートを Composer で入れます。

bash
composer require symfony/mailgun-mailer symfony/http-client

次に、config/mail.php を2か所変えます。まず、既定のメイラーを mailgun にします。

php
'default' => env('MAIL_MAILER', 'mailgun'),

次に、mailers の配列に、次の設定を足します。

php
'mailgun' => [
    'transport' => 'mailgun',
    // 'client' => [
    //     'timeout' => 5,
    // ],
],

既定のメイラーを決めたら、config/services.php に、次の設定を足します。

php
'mailgun' => [
    'domain' => env('MAILGUN_DOMAIN'),
    'secret' => env('MAILGUN_SECRET'),
    'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
    'scheme' => 'https',
],

アメリカ以外の Mailgun のリージョン(サービスの地域)を使うなら、services の設定で、その地域のエンドポイント(接続先)を決められます。

php
'mailgun' => [
    'domain' => env('MAILGUN_DOMAIN'),
    'secret' => env('MAILGUN_SECRET'),
    'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),
    'scheme' => 'https',
],

Postmark#

Symfony の Postmark Mailer のトランスポートを Composer で入れます。

bash
composer require symfony/postmark-mailer symfony/http-client

次に、config/mail.php の default を postmark にします。既定のメイラーを決めたら、config/services.php に、次の設定があることを確かめます。

php
'postmark' => [
    'key' => env('POSTMARK_API_KEY'),
],

メイラーごとに、Postmark のメッセージストリーム(メールの送り先の分け方)を決めたいときは、config/mail.php のメイラーの設定に、message_stream_id を足します。

php
'postmark' => [
    'transport' => 'postmark',
    'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
    // 'client' => [
    //     'timeout' => 5,
    // ],
],

こうすれば、メッセージストリームがちがう Postmark のメイラーを、複数作ることもできます。

Resend#

Resend の PHP SDK(PHP から Resend を使うための部品のセット)を Composer で入れます。

bash
composer require resend/resend-php

次に、config/mail.php の default を resend にします。既定のメイラーを決めたら、config/services.php に、次の設定があることを確かめます。

php
'resend' => [
    'key' => env('RESEND_API_KEY'),
],

Amazon SES#

Amazon SES を使うには、まず Amazon AWS の PHP 用 SDK を入れます。Composer で入れられます。

bash
composer require aws/aws-sdk-php

次に、config/mail.php の default を ses にします。config/services.php に、次の設定があることを確かめます。

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 を足します。

php
'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'),
],

SES の購読管理(配信の停止などを受け付ける機能)を使うには、メールの headers メソッドが返す配列に、X-Ses-List-Management-Options というヘッダーを入れます(headers は、後の「ヘッダー」の節にあります)。

php
/**
 * Get the message headers.
 */
public function headers(): Headers
{
    return new Headers(
        text: [
            'X-Ses-List-Management-Options' => 'contactListName=MyContactList;topicName=MyTopic',
        ],
    );
}

SES のテナント(利用者ごとの区分)を通してメールを送るには、headers メソッドから X-Ses-Tenant-Name というヘッダーを返します。Laravel は、その値を、SES に TenantName として渡します。

php
public function headers(): Headers
{
    return new Headers(
        text: [
            'X-Ses-Tenant-Name' => 'tenant-id',
        ],
    );
}

メールを送るとき、AWS SDK の SendEmail に、Laravel から追加で渡したい設定があれば、ses の設定に options の配列を書きます。

php
'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'],
        ],
    ],
],

送れなかったときの予備(フェイルオーバー)#

メールを送るのに使っている外のサービスが、止まっていることもあります。そんなときのために、本命の送り方がだめなときに使う、予備の送り方を決めておけます。

mail 設定の中に、failover のトランスポートを使うメイラーを作ります。そのメイラーの設定に、使いたいメイラーを、使う順に並べた mailers の配列を書きます。

php
'mailers' => [
    'failover' => [
        'transport' => 'failover',
        'mailers' => [
            'postmark',
            'mailgun',
            'sendmail',
        ],
        'retry_after' => 60,
    ],

    // ...
],

使うには、.env で、そのメイラーを既定のメイラーにします。

ini
MAIL_MAILER=failover

順番に使い分ける(ラウンドロビン)#

roundrobin のトランスポートは、メールを送る仕事を、複数のメイラーに分けて配ります。mail 設定に、roundrobin のトランスポートを使うメイラーを作ります。そのメイラーの設定に、配る先にしたいメイラーの mailers の配列を書きます。

php
'mailers' => [
    'roundrobin' => [
        'transport' => 'roundrobin',
        'mailers' => [
            'ses',
            'postmark',
        ],
        'retry_after' => 60,
    ],

    // ...
],

作ったら、mail 設定の default に、その名前を書いて、既定のメイラーにします。

php
'default' => env('MAIL_MAILER', 'roundrobin'),

ラウンドロビンは、並べたメイラーのうち、まず1つをランダムに選び、そのあとのメールごとに、次のメイラーへ切りかえます。failover は「止まらないこと」(高可用性)を助けますが、roundrobin は「負荷を分けること」(ロードバランシング)を助けます。

トランスポート 説明
failover 本命がだめなとき、並べた順に別の送り方を試す
roundrobin 送るたびに、並べた送り方を順に使い分ける

メイラブルを作る#

Laravel のアプリでは、送るメール1種類ごとに、「メイラブル」のクラスを作ります。クラスは app/Mail に置きます。フォルダが見つからなくても大丈夫です。最初のメイラブルを make:mail コマンドで作ると、自動で作られます。

bash
php artisan make:mail OrderShipped

メイラブルを書く#

メイラブルのクラスを作ったら、開いて中身を見てみましょう。設定は、envelope・content・attachments などのメソッドに書きます。

envelope は、Illuminate\Mail\Mailables\Envelope を返します。メールの件名と、ときには宛先を決めます。content は、Illuminate\Mail\Mailables\Content を返します。メールの本文を作る Blade テンプレート(画面の見た目を書いたファイル)を決めます。

送り主を決める#

envelope で決める#

まず、メールの送り主(「差出人」)を決める方法を見ましょう。送り主を決める方法は2つあります。1つ目は、メールの envelope に、差出人(from)を書く方法です。

php
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;

/**
 * Get the message envelope.
 */
public function envelope(): Envelope
{
    return new Envelope(
        from: new Address('jeffrey@example.com', 'Jeffrey Way'),
        subject: 'Order Shipped',
    );
}

返信先(replyTo)も決められます。

php
return new Envelope(
    from: new Address('jeffrey@example.com', 'Jeffrey Way'),
    replyTo: [
        new Address('taylor@example.com', 'Taylor Otwell'),
    ],
    subject: 'Order Shipped',
);

全体の差出人を決める#

アプリのメールが全部、同じ差出人なら、メイラブルごとに書くのは面倒です。かわりに、config/mail.php に、全体の差出人(from)を書けます。メイラブルに差出人がなければ、これが使われます。

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

全体の返信先(reply_to)も、config/mail.php に書けます。

php
'reply_to' => [
    'address' => 'example@example.com',
    'name' => 'App Name',
],

ビューを決める#

メイラブルの content メソッドで、view(メールの中身を作るのに使うテンプレート)を決めます。メールの中身は、ふつう Blade テンプレートで作るので、メールの HTML も、Blade の機能を全部使って作れます。

php
/**
 * Get the message content definition.
 */
public function content(): Content
{
    return new Content(
        view: 'mail.orders.shipped',
    );
}

補足

メールのテンプレートを入れておく resources/views/mail フォルダを作るとよいでしょう。ただし、resources/views の中なら、どこに置いても自由です。

テキストだけのメール#

メールのテキスト版(飾りのない文字だけの版)を作りたいときは、Content の定義に、テキスト用のテンプレートを決めます。view と同じように、text にテンプレートの名前を書きます。HTML 版とテキスト版の両方を作れます。

php
/**
 * Get the message content definition.
 */
public function content(): Content
{
    return new Content(
        view: 'mail.orders.shipped',
        text: 'mail.orders.shipped-text'
    );
}

分かりやすいように、view のかわりに html と書くこともできます(同じ意味です)。

php
return new Content(
    html: 'mail.orders.shipped',
    text: 'mail.orders.shipped-text'
);

ビューにデータを渡す#

メールの HTML を作るときに使うデータを、ビューへ渡したいことが多いはずです。渡し方は2つあります。

public のプロパティで渡す#

1つ目は、メイラブルのクラスの public のプロパティ(クラスの中の変数)です。public のプロパティは、自動でビューで使えます。たとえば、コンストラクター(クラスからものを作るときに最初に動くメソッド)でデータを受け取り、public のプロパティに入れます。

php
<?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;

    /**
     * Create a new message instance.
     */
    public function __construct(
        public Order $order,
    ) {}

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'mail.orders.shipped',
        );
    }
}

public のプロパティに入れたデータは、ほかの Blade のデータと同じように、ビューの中で使えます。

blade
<div>
    Price: {{ $order->price }}
</div>

with で渡す#

メールのテンプレートに渡す前に、データの形を整えたいときは、Content の with で、自分でデータを渡します。データはふつうコンストラクターで受け取りますが、自動でビューに渡らないように、protected か private のプロパティ(クラスの外から見えないプロパティ)に入れます。

php
<?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;

    /**
     * Create a new message instance.
     */
    public function __construct(
        protected Order $order,
    ) {}

    /**
     * Get the message content definition.
     */
    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 に、ファイルの場所を渡す方法です。

php
use Illuminate\Mail\Mailables\Attachment;

/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [
        Attachment::fromPath('/path/to/file'),
    ];
}

添付ファイルに、表示する名前や MIME タイプ(ファイルの種類を表す名前)を決めたいときは、as と withMime を使います。

php
/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [
        Attachment::fromPath('/path/to/file')
            ->as('name.pdf')
            ->withMime('application/pdf'),
    ];
}

ディスクにあるファイルを添付する#

ファイルの保存先(ディスク)に置いたファイルは、fromStorage で添付できます。

php
/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [
        Attachment::fromStorage('/path/to/file'),
    ];
}

もちろん、名前と MIME タイプも決められます。

php
/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [
        Attachment::fromStorage('/path/to/file')
            ->as('name.pdf')
            ->withMime('application/pdf'),
    ];
}

既定ではないディスクを使うなら、fromStorageDisk を使います。

php
/**
 * Get the attachments for the message.
 *
 * @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 には、生のデータを返すクロージャと、添付ファイルの名前を渡します。

php
/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [
        Attachment::fromData(fn () => $this->pdf, 'Report.pdf')
            ->withMime('application/pdf'),
    ];
}
メソッド 説明
Attachment::fromPath ファイルの場所を渡して添付する
Attachment::fromStorage 既定のディスクのファイルを添付する
Attachment::fromStorageDisk 決めたディスクのファイルを添付する
Attachment::fromData 生のデータを返すクロージャと名前で添付する
as 添付ファイルの表示名を決める
withMime MIME タイプを決める

本文に画像を埋め込む#

メールの本文に画像を埋め込む(インライン添付)のは、ふつう面倒です。Laravel では、メールのテンプレートの中の $message 変数の embed で、簡単に埋め込めます。$message は、すべてのメールのテンプレートで自動で使えるので、自分で渡す必要はありません。

blade
<body>
    Here is an image:

    <img src="{{ $message->embed($pathToImage) }}">
</body>

注意

$message 変数は、テキスト版のテンプレートでは使えません。テキストのメールには、埋め込みの画像がないからです。

生のデータの画像を埋め込む#

画像の生のデータがすでにあるなら、$message の embedData で埋め込めます。そのとき、埋め込む画像につけるファイル名を渡します。

blade
<body>
    Here is an image from raw data:

    <img src="{{ $message->embedData($data, 'example-image.jpg') }}">
</body>

添付できるオブジェクト#

ファイルの場所の文字列を渡して添付するだけで足りることも多いです。ただ、アプリの中で、添付したいものがクラスで表されていることもあります。たとえば、写真を添付するなら、その写真を表す Photo モデルがあるかもしれません。そんなとき、Photo モデルをそのまま添付に渡せたら、便利ですね。「添付できるオブジェクト」(Attachable)で、それができます。

まず、メールに添付できるようにしたいオブジェクトに、Illuminate\Contracts\Mail\Attachable を付けます。このインターフェイス(決まりごと)は、Illuminate\Mail\Attachment を返す toMailAttachment メソッドを書くことを決めています。

php
<?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.
     */
    public function toMailAttachment(): Attachment
    {
        return Attachment::fromPath('/path/to/file');
    }
}

添付できるオブジェクトを作ったら、メールの attachments メソッドから、そのオブジェクトを返せます。

php
/**
 * Get the attachments for the message.
 *
 * @return array<int, \Illuminate\Mail\Mailables\Attachment>
 */
public function attachments(): array
{
    return [$this->photo];
}

添付のデータが、Amazon S3 のような、遠くのファイルの保存先にあることもあります。そのときも、アプリのディスクにあるデータから、添付を作れます。

php
// 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);

メモリの中にあるデータからも、添付を作れます。fromData に、添付の生のデータを返すクロージャを渡します。

php
return Attachment::fromData(fn () => $this->content, 'Photo Name');

添付を調整するメソッドもあります。たとえば、as と withMime で、ファイルの名前と MIME タイプを決められます。

php
return Attachment::fromPath('/path/to/file')
    ->as('Photo Name')
    ->withMime('image/jpeg');

ヘッダー#

送るメールに、追加のヘッダー(メールの見えない付属情報)をつけたいことがあります。たとえば、自分で決めた Message-Id や、ほかの好きな文字のヘッダーです。

メイラブルに headers メソッドを書きます。このメソッドは、Illuminate\Mail\Mailables\Headers を返します。messageId・references・text の3つの引数を受け取り、必要なものだけ渡せます。

php
use Illuminate\Mail\Mailables\Headers;

/**
 * Get the message headers.
 */
public function headers(): Headers
{
    return new Headers(
        messageId: 'custom-message-id@example.com',
        references: ['previous-message@example.com'],
        text: [
            'X-Custom-Header' => 'Custom Value',
        ],
    );
}
引数 説明
messageId メールの Message-Id
references 前のメールの ID の配列
text 好きな文字のヘッダーの配列

タグとメタデータ#

Mailgun や Postmark などのメールのサービスには、メールの「タグ」と「メタデータ」(付属のデータ)に対応しているものがあります。アプリが送ったメールを、グループ分けしたり追いかけたりするのに使えます。Envelope の定義で、タグとメタデータをつけます。

php
use Illuminate\Mail\Mailables\Envelope;

/**
 * Get the message 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 や Postmark を使っているなら、それぞれのサービスの説明で、タグとメタデータの詳しいことを調べられます。

Amazon SES でメールを送るなら、SES の「タグ」をメールにつけるために、metadata を使います。

Symfony のメッセージを調整する#

Laravel のメールの機能は、Symfony Mailer で動いています。送る前に、Symfony のメッセージ(Email)を受け取って動くコールバックを登録できます。送る前にメールを細かく調整できます。Envelope の定義に、using を書きます。

php
use Illuminate\Mail\Mailables\Envelope;
use Symfony\Component\Mime\Email;

/**
 * Get the message envelope.
 */
public function envelope(): Envelope
{
    return new Envelope(
        subject: 'Order Shipped',
        using: [
            function (Email $message) {
                // ...
            },
        ]
    );
}

Markdown のメイラブル#

Markdown のメイラブルは、メールの通知(通知)で使える、できあがったテンプレートと部品を、メイラブルでも使えるようにするものです。メッセージを Markdown で書くので、Laravel が、見やすくて画面の大きさに合わせて変わる HTML のメールを作ってくれます。テキスト版も、自動で作られます。

Markdown のメイラブルを作る#

Markdown のテンプレートつきのメイラブルを作るには、make:mail の --markdown オプションを使います。

bash
php artisan make:mail OrderShipped --markdown=mail.orders.shipped

そして、メイラブルの content メソッドで Content を決めるとき、view のかわりに markdown を使います。

php
use Illuminate\Mail\Mailables\Content;

/**
 * Get the message content definition.
 */
public function content(): Content
{
    return new Content(
        markdown: 'mail.orders.shipped',
        with: [
            'url' => $this->orderUrl,
        ],
    );
}

Markdown のメッセージを書く#

Markdown のメイラブルは、Blade のコンポーネント(何度も使う画面の部品)と Markdown の書き方を組み合わせて書きます。Laravel が用意したメールの部品を使いながら、簡単にメールを作れます。

blade
<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 の決まりで、字下げした内容はコードのブロックとして表示されてしまいます。

使える部品は、次のとおりです。

部品 説明
x-mail::message メール全体を包む
x-mail::button 中央に置くボタンのリンク
x-mail::panel 目立たせたい文章を、背景色をかえた枠に入れる
x-mail::table Markdown の表を HTML の表に変える

ボタン#

ボタンの部品は、中央にボタンのリンクを出します。引数は、url と、省略できる color です。使える色は、primary・success・error です。1つのメールに、ボタンをいくつでも置けます。

blade
<x-mail::button :url="$url" color="success">
View Order
</x-mail::button>

パネル#

パネルの部品は、決まったかたまりの文章を、ほかの部分と少し背景色のちがう枠の中に出します。目立たせたい文章に向いています。

blade
<x-mail::panel>
This is the panel content.
</x-mail::panel>

表#

表の部品は、Markdown の表を HTML の表に変えます。中身に Markdown の表を渡します。列の位置(左・中央・右)は、ふつうの Markdown の表の書き方で決められます。

blade
<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 のタグがついたファイルを書き出します。

bash
php artisan vendor:publish --tag=laravel-mail

このコマンドは、Markdown のメールの部品を resources/views/vendor/mail に書き出します。mail フォルダには、html と text のフォルダがあり、使えるすべての部品の HTML 版とテキスト版が入っています。好きなように書きかえられます。

CSS を書きかえる#

書き出したあと、resources/views/vendor/mail/html/themes に、default.css があります。この CSS を書きかえると、Markdown のメールの HTML 版に、自動で反映されます。そのとき CSS は、インライン CSS(要素に直接書く CSS)の形に変えて入れられます。

Laravel の Markdown の部品のために、まったく新しいテーマを作りたいときは、html/themes に CSS ファイルを置きます。名前をつけて保存したら、アプリの config/mail.php の theme を、その新しいテーマの名前にします。

メイラブル1つだけテーマを変えたいときは、メイラブルのクラスの $theme プロパティに、使いたいテーマの名前を書きます。

メールを送る#

メールを送るには、Mail ファサードの to を使います。to は、メールアドレス・ユーザーのインスタンス(クラスから作った実物)・ユーザーのコレクション(入れ物)を受け取ります。オブジェクトやコレクションを渡すと、その email と name のプロパティから宛先が決まります。そのため、オブジェクトにこの2つのプロパティがあることを確かめてください。宛先を決めたら、メイラブルのインスタンスを send に渡します。

php
<?php

namespace App\Http\Controllers;

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
{
    /**
     * Ship the given order.
     */
    public function store(Request $request): RedirectResponse
    {
        $order = Order::findOrFail($request->order_id);

        // Ship the order...

        Mail::to($request->user())->send(new OrderShipped($order));

        return redirect('/orders');
    }
}

宛先は「to」だけではありません。「to」「cc」「bcc」を、メソッドをつなげて決められます。

php
Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new OrderShipped($order));

宛先を順に回して送る#

宛先の配列を順に回して、1人ずつにメールを送りたいことがあります。ただし、to は、メイラブルの宛先の一覧に、メールアドレスを足していきます。そのため、ループのたびに、前の人全員へ、またメールが送られてしまいます。だから、宛先ごとに、メイラブルを作り直してください。

php
foreach (['taylor@example.com', 'dries@example.com'] as $recipient) {
    Mail::to($recipient)->send(new OrderShipped($order));
}

メイラーを選んで送る#

ふつう、Laravel は、mail 設定の default のメイラーでメールを送ります。mailer で、決めたメイラーの設定を使って送れます。

php
Mail::mailer('postmark')
    ->to($request->user())
    ->send(new OrderShipped($order));

メールをキューに入れる#

メールをキューに入れる#

メールを送る処理は、アプリの応答を遅くすることがあります。そのため、メールを裏で送るために、キューに入れる開発者が多いです。Laravel のキュー(時間のかかる仕事を順番待ちの列に並べ、裏で片づけるしくみ)を使えば、簡単です。メールをキューに入れるには、宛先を決めたあと、Mail ファサードの queue を使います。

php
Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue(new OrderShipped($order));

この方法は、ジョブ(キューに並べる1つ1つの仕事)を自動でキューに入れて、メールが裏で送られるようにしてくれます。使う前に、キューを設定してください。

少し待ってから送る#

キューに入れたメールの送信を遅らせたいときは、later を使います。第1引数に、いつ送るかを表す DateTime を渡します。

php
Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later(now()->plus(minutes: 10), new OrderShipped($order));

送り先のキューを決める#

make:mail で作ったメイラブルは、すべて Illuminate\Bus\Queueable のトレイト(いくつものクラスに同じ機能を足す部品)を使っています。そのため、メイラブルのインスタンスに onQueue と onConnection を呼んで、メールの接続とキューの名前を決められます。

php
$message = (new OrderShipped($order))
    ->onConnection('sqs')
    ->onQueue('emails');

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue($message);

メイラブルのクラスに、PHP の属性 Connection と Queue を付けても、接続とキューを決められます。

php
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;

#[Connection('sqs')]
#[Queue('emails')]
class OrderShipped extends Mailable
{
    // ...
}

いつもキューに入れる#

いつもキューに入れたいメイラブルには、ShouldQueue を付けます。これで、send で送っても、そのメイラブルはキューに入ります。

php
use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    // ...
}

キューのメールとデータベースのトランザクション#

トランザクション(複数の書き込みを、まとめて確定するか取り消す仕組み)の中でキューのメールを出すと、確定よりも先に処理されることがあります。そのときは、トランザクションの中で変えたデータがまだ反映されていなかったり、作ったはずのデータがまだ無かったりします。メイラブルがそのデータを使っていると、思わぬエラーが出ます。

キュー接続の after_commit が false でも、メールを送るときに afterCommit を呼べば、開いているトランザクションがすべて確定したあとで、そのメイラブルを送れます。

php
Mail::to($request->user())->send(
    (new OrderShipped($order))->afterCommit()
);

メイラブルのコンストラクターの中で、afterCommit を呼んでも決められます。

php
<?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;

    /**
     * Create a new message instance.
     */
    public function __construct()
    {
        $this->afterCommit();
    }
}

補足

この問題への対策は、キューのページの「データベースのトランザクションとジョブ」にくわしく書いてあります。

キューのメールが失敗したとき#

キューに入れたメールが失敗したとき、メイラブルのクラスに failed メソッドがあれば、それが呼ばれます。失敗の原因の Throwable が渡されます。

php
<?php

namespace App\Mail;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Throwable;

class OrderDelayed extends Mailable implements ShouldQueue
{
    use SerializesModels;

    /**
     * Handle a queued email's failure.
     */
    public function failed(Throwable $exception): void
    {
        // ...
    }
}

メイラブルの HTML を取り出す#

メールを送らずに、メイラブルの HTML の中身だけを取り出したいことがあります。メイラブルの render を呼ぶと、できあがった HTML を文字列で返してくれます。

php
use App\Mail\InvoicePaid;
use App\Models\Invoice;

$invoice = Invoice::find(1);

return (new InvoicePaid($invoice))->render();

ブラウザでメイラブルを確かめる#

メイラブルのテンプレートを作るときは、ふつうの Blade のテンプレートのように、ブラウザですぐ確かめられると便利です。そのため、Laravel では、ルートのクロージャやコントローラーから、メイラブルをそのまま返せます。メイラブルを返すと、HTML に組み立てられて、ブラウザに表示されます。本物のメールアドレスに送らなくても、見た目をすぐに確かめられます。

php
Route::get('/mailable', function () {
    $invoice = App\Models\Invoice::find(1);

    return new App\Mail\InvoicePaid($invoice);
});

メイラブルを多言語にする#

Laravel では、今のリクエストのロケール(言語の設定)とは別のロケールで、メイラブルを送れます。キューに入れたときも、そのロケールを覚えています。

そのために、Mail ファサードには、locale があります。送りたい言語を決めます。メイラブルのテンプレートから中身を作るあいだだけ、アプリがそのロケールに切りかわり、終わったら、前のロケールに戻ります。

php
Mail::to($request->user())->locale('es')->send(
    new OrderShipped($order)
);

利用者が選んだ言語を使う#

利用者ごとに、選んだ言語を保存しているアプリもあります。1つ以上のモデルに、HasLocalePreference を付けると、保存されたその言語を、メールを送るときに使うよう、Laravel に伝えられます。

php
use Illuminate\Contracts\Translation\HasLocalePreference;

class User extends Model implements HasLocalePreference
{
    /**
     * Get the user's preferred locale.
     */
    public function preferredLocale(): string
    {
        return $this->locale;
    }
}

このインターフェイスを付けると、そのモデルにメイラブルや通知を送るとき、Laravel が自動で、選ばれた言語を使います。そのため、このインターフェイスを使うときは、locale を呼ぶ必要はありません。

php
Mail::to($request->user())->send(new OrderShipped($order));

テスト#

メールの中身をテストする#

Laravel には、メイラブルの形を調べるメソッドがいろいろあります。また、メイラブルに、期待どおりの内容が入っているかを確かめるための、便利なメソッドもいくつかあります。

Pest(PHP のテストの道具)で書く場合です。

php
use App\Mail\InvoicePaid;
use App\Models\User;

test('mailable content', function () {
    $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->assertDontSeeInHtml('Invoice Not Paid');
    $mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);

    $mailable->assertSeeInText($user->email);
    $mailable->assertDontSeeInText('Invoice Not Paid');
    $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']);
});

PHPUnit(PHP のテストの道具)で書く場合です。

php
use App\Mail\InvoicePaid;
use App\Models\User;

public function test_mailable_content(): void
{
    $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->assertDontSeeInHtml('Invoice Not Paid');
    $mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);

    $mailable->assertSeeInText($user->email);
    $mailable->assertDontSeeInText('Invoice Not Paid');
    $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']);
}

「HTML」のアサーションは、メイラブルの HTML 版に、決めた文字列が含まれているかを確かめます。「text」のアサーションは、テキスト版に含まれているかを確かめます。

メソッド 説明
assertFrom 差出人を確かめる
assertTo 宛先(to)を確かめる
assertHasCc cc があることを確かめる
assertHasBcc bcc があることを確かめる
assertHasReplyTo 返信先があることを確かめる
assertHasSubject 件名を確かめる
assertHasTag タグがあることを確かめる
assertHasMetadata メタデータがあることを確かめる
assertSeeInHtml HTML 版に文字列があることを確かめる
assertDontSeeInHtml HTML 版に文字列がないことを確かめる
assertSeeInOrderInHtml HTML 版に、文字列が順番どおりにあることを確かめる
assertSeeInText テキスト版に文字列があることを確かめる
assertDontSeeInText テキスト版に文字列がないことを確かめる
assertSeeInOrderInText テキスト版に、文字列が順番どおりにあることを確かめる
assertHasAttachment 添付ファイルがあることを確かめる
assertHasAttachedData 生のデータの添付があることを確かめる
assertHasAttachmentFromStorage ディスクのファイルの添付があることを確かめる
assertHasAttachmentFromStorageDisk 決めたディスクのファイルの添付があることを確かめる

メールを送ったかをテストする#

メイラブルの中身のテストは、「決まった利用者に、そのメイラブルを送った」ことを確かめるテストとは、別にするのがおすすめです。ふつう、メイラブルの中身は、テストしたいコードには関係ありません。Laravel に「そのメイラブルを送るように言った」ことだけ確かめれば、足ります。

Mail ファサードの fake を呼ぶと、メールが実際には送られなくなります。そのあと、メイラブルがユーザーに送られることになったかや、メイラブルが受け取ったデータまで、アサーション(「こうなっているはず」を確かめる命令)で調べられます。

Pest で書く場合です。

php
<?php

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

test('orders can be shipped', function () {
    Mail::fake();

    // Perform order shipping...

    // Assert that no mailables were sent...
    Mail::assertNothingSent();

    // Assert that a mailable was sent...
    Mail::assertSent(OrderShipped::class);

    // Assert a mailable was sent twice...
    Mail::assertSent(OrderShipped::class, 2);

    // Assert a mailable was sent to an email address...
    Mail::assertSent(OrderShipped::class, 'example@laravel.com');

    // Assert a mailable was sent to multiple email addresses...
    Mail::assertSent(OrderShipped::class, ['example@laravel.com', '...']);

    // Assert a mailable was not sent...
    Mail::assertNotSent(AnotherMailable::class);

    // Assert a mailable was sent twice...
    Mail::assertSentTimes(OrderShipped::class, 2);

    // Assert that a mailable was sent exactly once...
    Mail::assertSentOnce(OrderShipped::class);

    // Assert 3 total mailables were sent...
    Mail::assertSentCount(3);
});

PHPUnit で書く場合です。

php
<?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();

        // Perform order shipping...

        // Assert that no mailables were sent...
        Mail::assertNothingSent();

        // Assert that a mailable was sent...
        Mail::assertSent(OrderShipped::class);

        // Assert a mailable was sent twice...
        Mail::assertSent(OrderShipped::class, 2);

        // Assert a mailable was sent to an email address...
        Mail::assertSent(OrderShipped::class, 'example@laravel.com');

        // Assert a mailable was sent to multiple email addresses...
        Mail::assertSent(OrderShipped::class, ['example@laravel.com', '...']);

        // Assert a mailable was not sent...
        Mail::assertNotSent(AnotherMailable::class);

        // Assert a mailable was sent twice...
        Mail::assertSentTimes(OrderShipped::class, 2);

        // Assert that a mailable was sent exactly once...
        Mail::assertSentOnce(OrderShipped::class);

        // Assert 3 total mailables were sent...
        Mail::assertSentCount(3);
    }
}

メイラブルを、裏で送るためにキューに入れているなら、assertSent のかわりに assertQueued を使います。

php
Mail::assertQueued(OrderShipped::class);
Mail::assertQueuedOnce(OrderShipped::class);
Mail::assertNotQueued(OrderShipped::class);
Mail::assertNothingQueued();
Mail::assertQueuedCount(3);

送ったメイラブルとキューに入れたメイラブルを合わせた総数は、assertOutgoingCount で確かめられます。

php
Mail::assertOutgoingCount(3);

assertSent・assertNotSent・assertQueued・assertNotQueued には、条件を書いたクロージャ(true か false を返す関数)を渡せます。条件に合うメイラブルが1つでも送られていれば、成功です。

php
Mail::assertSent(function (OrderShipped $mail) use ($order) {
    return $mail->order->id === $order->id;
});

Mail ファサードのアサーションに渡したクロージャが受け取るメイラブルには、中身を調べるための便利なメソッドがあります。

php
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) {
    return $mail->hasTo($user->email) &&
           $mail->hasCc('...') &&
           $mail->hasBcc('...') &&
           $mail->hasReplyTo('...') &&
           $mail->hasFrom('...') &&
           $mail->hasSubject('...') &&
           $mail->hasMetadata('order_id', $mail->order->id) &&
           $mail->usesMailer('ses');
});

メイラブルの添付ファイルを調べる便利なメソッドもあります。

php
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 を使います。

php
Mail::assertNothingOutgoing();

Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) {
    return $mail->order->id === $order->id;
});
メソッド 説明
assertNothingSent メールが1つも送られていないことを確かめる
assertSent メイラブルが送られたことを確かめる(回数や宛先も指定できる)
assertNotSent メイラブルが送られていないことを確かめる
assertSentTimes メイラブルが決めた回数送られたことを確かめる
assertSentOnce メイラブルがちょうど1回送られたことを確かめる
assertSentCount 送られたメイラブルの総数を確かめる
assertQueued メイラブルがキューに入ったことを確かめる
assertQueuedOnce メイラブルがちょうど1回キューに入ったことを確かめる
assertNotQueued メイラブルがキューに入っていないことを確かめる
assertNothingQueued 何もキューに入っていないことを確かめる
assertQueuedCount キューに入ったメイラブルの総数を確かめる
assertOutgoingCount 送られたものと、キューに入ったものの総数を確かめる
assertNothingOutgoing 送られたものも、キューに入ったものもないことを確かめる
assertNotOutgoing 条件に合うメイラブルが、送られても、キューに入ってもいないことを確かめる

クロージャが受け取るメイラブルで使える、中身を調べるメソッドは、次のとおりです。

メソッド 説明
hasTo 宛先(to)があるか
hasCc cc があるか
hasBcc bcc があるか
hasReplyTo 返信先があるか
hasFrom 差出人が合っているか
hasSubject 件名が合っているか
hasMetadata メタデータがあるか
usesMailer 決めたメイラーを使っているか
hasAttachment 添付ファイルがあるか

メールと手元の開発#

メールを送るアプリを開発しているとき、本物のメールアドレスには、実際には送りたくないはずです。Laravel には、手元の開発で、実際の送信を「止める」方法がいくつかあります。

ログドライバー#

log のメールドライバーは、メールを送るかわりに、すべてのメールをログのファイルに書き出します。あとで中身を調べられます。ふつうは、手元の開発のときだけ使います。環境ごとにアプリを設定する方法は、設定のページを見てください。

HELO・Mailtrap・Mailpit#

そのほか、HELO や Mailtrap のようなサービスと、smtp ドライバーを使い、メールを「にせものの」メールボックスに送る方法もあります。本物のメールソフトのような画面で、メールを見られます。Mailtrap のメールを見る画面で、できあがったメールを実際に調べられるのが、この方法の利点です。

Laravel Sail(Laravel を Docker で動かす道具)を使っているなら、Mailpit でメッセージを確かめられます。Sail が動いているあいだ、http://localhost:8025 で、Mailpit の画面を開けます。

全体の宛先を決める#

最後に、Mail ファサードの alwaysTo を呼ぶと、全体の「to」の宛先を決められます。ふつうは、アプリのサービスプロバイダの boot メソッドで呼びます。

php
use Illuminate\Support\Facades\Mail;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    if ($this->app->environment('local')) {
        Mail::alwaysTo('taylor@example.com');
    }
}

alwaysTo を使うと、メールにつけた cc と bcc の宛先は、取り除かれます。

方法 説明
log ドライバー 送らずに、ログのファイルに書き出す
HELO・Mailtrap にせもののメールボックスに送って、メールソフトの画面で見る
Mailpit Sail で動かすとき、http://localhost:8025 で見る
alwaysTo すべてのメールの宛先を、決めた1つにする

メールのイベント#

Laravel は、メールを送るとき、2つのイベントを出します。MessageSending は、メッセージを送る前に、MessageSent は、送ったあとに出ます。これらは、メールを「送る」ときに出るもので、キューに入れたときではないことに気をつけてください。アプリの中で、これらのイベントのリスナーを作れます。

php
use Illuminate\Mail\Events\MessageSending;
// use Illuminate\Mail\Events\MessageSent;

class LogMessage
{
    /**
     * Handle the event.
     */
    public function handle(MessageSending $event): void
    {
        // ...
    }
}

自分で作る送り方(カスタムトランスポート)#

Laravel には、いろいろなメールの送り方が入っています。それでも、Laravel が最初から対応していない別のサービスで送りたいなら、自分で送り方を書けます。まず、Symfony\Component\Mailer\Transport\AbstractTransport を継ぐクラスを作ります。そして、doSend と __toString のメソッドを書きます。

php
<?php

namespace App\Mail;

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
{
    /**
     * Create a new Mailchimp transport instance.
     */
    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(),
        ]]);
    }

    /**
     * Get the string representation of the transport.
     */
    public function __toString(): string
    {
        return 'mailchimp';
    }
}

自分の送り方を作ったら、Mail ファサードの extend で登録します。ふつうは、アプリの AppServiceProvider の boot メソッドに書きます。extend に渡すクロージャには、$config の引数が渡されます。この引数には、config/mail.php の中で、そのメイラーに決めた設定の配列が入っています。

php
use App\Mail\MailchimpTransport;
use Illuminate\Support\Facades\Mail;
use MailchimpTransactional\ApiClient;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Mail::extend('mailchimp', function (array $config = []) {
        $client = new ApiClient;

        $client->setApiKey($config['key']);

        return new MailchimpTransport($client);
    });
}

送り方を作って登録したら、config/mail.php に、その新しい送り方を使うメイラーの定義を作れます。

php
'mailchimp' => [
    'transport' => 'mailchimp',
    'key' => env('MAILCHIMP_API_KEY'),
    // ...
],

そのほかの Symfony の送り方#

Laravel には、Mailgun や Postmark のような、Symfony が管理している送り方に、最初から対応しているものがあります。それ以外の、Symfony が管理する送り方を、Laravel に足したいこともあります。必要な Symfony のメーラーを Composer で入れ、Laravel に登録します。たとえば、「Brevo」(以前の「Sendinblue」)の Symfony のメーラーを入れて登録する例です。

bash
composer require symfony/brevo-mailer symfony/http-client

Brevo のメーラーのパッケージを入れたら、アプリの services 設定に、Brevo の API の認証情報を足します。

php
'brevo' => [
    'key' => env('BREVO_API_KEY'),
],

次に、Mail ファサードの extend で、その送り方を Laravel に登録します。ふつうは、サービスプロバイダの boot メソッドに書きます。

php
use Illuminate\Support\Facades\Mail;
use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Mail::extend('brevo', function () {
        return (new BrevoTransportFactory)->create(
            new Dsn(
                'brevo+api',
                'default',
                config('services.brevo.key')
            )
        );
    });
}

送り方を登録したら、config/mail.php に、その新しい送り方を使うメイラーの定義を作れます。

php
'brevo' => [
    'transport' => 'brevo',
    // ...
],

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧