対象バージョン: Laravel 13.x / PHP 8.3+
Laravel では、送信するメールを Mailable というクラスで表します。この記事では、Mailable の作成から送信、実際には送らずに中身を確認する方法、テストでの検証までを順に説明します。SMTP サーバーや外部サービスのアカウントは使いません。新規プロジェクトの初期設定のまま試せます。
この記事で分かること
php artisan make:mailで Mailable を作り、件名・本文・データを定義する方法Mail::to()->send()で送信し、cc/bccを付ける方法- log メーラー、ブラウザプレビュー、
render()で送信内容を確認する方法 Mail::fake()とassertSent系メソッドで送信をテストする方法
前提
Laravel 13.x は PHP 8.3 以上が必要です。動作確認は laravel/framework v13.35.0 で行いました。ルーティングや Blade の基本は、【PHP】Laravel入門:インストールから簡単なサンプルアプリケーションの作成を参照してください。
メールの設定を確認する
メールの設定は config/mail.php にあります。mailers 配列にメーラー(送信方法)ごとの設定が並び、default で既定のメーラーを選びます。
'default' => env('MAIL_MAILER', 'log'),
Laravel 13.x の新規プロジェクトでは、.env が次の値になっています。
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
MAIL_MAILER=log なので、初期状態ではメールは実際には送られず、ログファイルに書き出されます。送信元(From)は config/mail.php の from で全体に設定され、MAIL_FROM_ADDRESS と MAIL_FROM_NAME から読み込まれます。
Mailable クラスを作る
Mailable は make:mail コマンドで作成します。ここでは発送通知メールを例にします。
php artisan make:mail ShippingNotice
クラスは app/Mail ディレクトリに置かれます。このディレクトリは最初の Mailable を作るときに自動で作成されます。
生成されたクラスは Illuminate\Mail\Mailable を継承し、次の3つのメソッドを持っています。
| メソッド | 戻り値 | 役割 |
|---|---|---|
envelope() |
Envelope |
件名などを定義する |
content() |
Content |
本文に使う Blade ビューを指定する |
attachments() |
配列 | 添付ファイル(初期状態は空) |
生成直後の content() には view: 'view.name' という仮の値が入っています。ビューファイルは作られないため、自分で用意します。
件名・本文・データを定義する
注文番号と顧客名を受け取るように書き換えます。
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ShippingNotice extends Mailable
{
use Queueable, SerializesModels;
public function __construct(
public string $orderNumber,
protected string $customerName,
) {}
public function envelope(): Envelope
{
return new Envelope(
subject: 'ご注文の商品を発送しました',
);
}
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
with: [
'customerName' => $this->customerName,
],
);
}
/**
* @return array<int, Attachment>
*/
public function attachments(): array
{
return [];
}
}
ビューにデータを渡す方法は2つあります。
- public プロパティ:
$orderNumberのような public プロパティは、そのままビューで使えます。 with:パラメータ:Contentのwith:で明示的に渡します。この場合、値は protected または private プロパティに持たせて、ビューへ自動で公開されないようにします。
ビューは resources/views/mail/orders/shipped.blade.php に作ります。
<!DOCTYPE html>
<html lang="ja">
<body>
<p>{{ $customerName }} 様</p>
<p>ご注文(注文番号: {{ $orderNumber }})の商品を発送しました。</p>
</body>
</html>
メールを送信する
送信には Mail ファサードを使います。to() に宛先を指定し、send() に Mailable のインスタンスを渡します。cc() と bcc() はメソッドチェーンで追加できます。
use App\Mail\ShippingNotice;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Route;
Route::get('/orders/ship', function () {
Mail::to('taro@example.com')
->cc('cc@example.com')
->bcc('bcc@example.com')
->send(new ShippingNotice('A-1001', '山田太郎'));
return 'sent';
});
公式ドキュメントによると、to() にはメールアドレスのほか、ユーザーのインスタンスやそのコレクションも渡せます。
make:mail で作ったクラスは ShouldQueue を実装していないため、send() はその場で同期的に送信します。キューを使う送信(Mail::to()->queue())もありますが、事前にキューの設定が必要です。
log メーラーで送信内容を確認する
MAIL_MAILER=log のとき、メールは送信されずにアプリケーションのログへ書き出されます。ローカル開発向けの仕組みです。新規プロジェクトでは storage/logs/laravel.log に、local.DEBUG のエントリとしてメール全体が記録されます。
上の /orders/ship にアクセスすると、次のように出力されます。
[2026-10-09 06:40:26] local.DEBUG: From: Laravel <hello@example.com>
To: taro@example.com
Cc: cc@example.com
Subject: =?utf-8?Q?=E3=81=94=E6=B3=A8=E6=96=87=E3=81=AE?=
=?utf-8?Q?=E5=95=86=E5=93=81=E3=82=92=E7=99=BA?=
=?utf-8?Q?=E9=80=81=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?=
MIME-Version: 1.0
Date: Fri, 09 Oct 2026 06:40:26 +0000
Message-ID: <821cf9c22755d50fcac46c47c3f8d2d6@example.com>
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE html>
<html lang="ja">
<body>
<p>山田太郎 様</p>
<p>ご注文(注文番号: A-1001)の商品を発送しました。</p>
</body>
</html>
ログを読むときは、次の3点に注意してください。
- 時刻は UTC: 新規プロジェクトでは
config/app.phpのtimezoneが'UTC'のため、ログの時刻は日本時間より9時間前になります。 - 日本語の件名はエンコードされる: 件名は
=?utf-8?Q?...?=の形式で記録されるため、そのままでは読めません。本文の HTML は読める形で出力されます。 - Bcc はログに出ない:
ToとCcは表示されますが、Bccの行は出力されません。Bcc の宛先は、後述するテストで確認します。
公式ドキュメントでは、log メーラーの代わりに HELO や Mailtrap などのサービスを smtp ドライバで使う方法や、Laravel Sail の Mailpit を使う方法も紹介されています。
送信せずにプレビューする
ブラウザで表示する
ルートやコントローラから Mailable を返すと、メールはブラウザに HTML として表示されます。このとき送信は行われません。
use App\Mail\ShippingNotice;
use Illuminate\Support\Facades\Route;
Route::get('/mailable/shipping-notice', function () {
return new ShippingNotice('A-1001', '山田太郎');
});
render() で HTML を取得する
render() を呼ぶと、評価済みの HTML を文字列で取得できます。こちらも送信はしません。
php artisan tinker
(new App\Mail\ShippingNotice('A-1002', '佐藤花子'))->render();
Markdown メールを使う
--markdown オプションを付けると、Markdown 形式のビュー付きで Mailable を作れます。
php artisan make:mail WelcomeMail --markdown=mail.welcome
生成されるクラスの content() は Content(markdown: 'mail.welcome') になり、resources/views/mail/welcome.blade.php も作成されます。
<x-mail::message>
# Introduction
The body of your message.
<x-mail::button :url="''">
Button Text
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
この Mailable をルートから返してブラウザで表示すると、ボタンを含むメール用のレイアウトで描画されます。
メール送信をテストする
テストの基本は【PHP】Laravelでテストを実装する方法で扱っています。ここではメール固有の部分を説明します。
Mail::fake() で送信を検証する
Mail::fake() を呼ぶと、メールは実際には送られません。そのうえで、送信されたかどうかを検証できます。
<?php
namespace Tests\Feature;
use App\Mail\ShippingNotice;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class ShippingNoticeTest extends TestCase
{
public function test_shipping_notice_is_sent(): void
{
Mail::fake();
$this->get('/orders/ship')->assertOk();
Mail::assertSent(ShippingNotice::class);
Mail::assertSent(ShippingNotice::class, function (ShippingNotice $mail) {
return $mail->hasTo('taro@example.com')
&& $mail->hasCc('cc@example.com')
&& $mail->hasBcc('bcc@example.com')
&& $mail->orderNumber === 'A-1001';
});
Mail::assertSentCount(1);
}
public function test_nothing_is_sent_when_route_not_called(): void
{
Mail::fake();
Mail::assertNothingSent();
}
}
| メソッド | 検証内容 |
|---|---|
Mail::assertSent(クラス名) |
指定した Mailable が送信された |
Mail::assertSent(クラス名, クロージャ) |
条件に合う Mailable が送信された |
Mail::assertSentCount(n) |
送信された Mailable が n 件 |
Mail::assertNothingSent() |
何も送信されていない |
クロージャ内の hasBcc() で、ログでは確認できない Bcc の宛先も検証できます。
1回だけ送信されたことを確認する
「ちょうど1回送信された」ことは、Mail::assertSentOnce() で確認できます。
Mail::assertSentOnce(ShippingNotice::class);
注意:
Mail::assertSentOnce()は Laravel 13.31 以降で使えます。 Laravel 13.0〜13.30.x にはこのメソッドがありません。使っているバージョンはphp artisan --versionで確認できます。13.31 より前のバージョンでは、回数を指定したassertSentを使います。
Mail::assertSent(ShippingNotice::class, 1);
メールの内容を検証する
件名や本文は、Mail::fake() を使わずに Mailable のインスタンスで直接検証できます。
public function test_shipping_notice_content(): void
{
$mailable = new ShippingNotice('A-1001', '山田太郎');
$mailable->assertHasSubject('ご注文の商品を発送しました');
$mailable->assertSeeInHtml('山田太郎 様');
$mailable->assertSeeInHtml('A-1001');
$mailable->assertDontSeeInHtml('password');
}
テストは次のコマンドで実行します。
php artisan test
まとめ
- Mailable は
php artisan make:mailで作り、envelope()に件名、content()にビューを定義する - ビューには public プロパティ、または
Contentのwith:でデータを渡す - 送信は
Mail::to()->send()。cc()/bcc()はチェーンで追加する - 新規プロジェクトは
MAIL_MAILER=logで、メールはstorage/logs/laravel.logに記録される。時刻は UTC、日本語の件名はエンコード表示、Bcc は表示されない - Mailable をルートから返すとブラウザでプレビューでき、
render()で HTML を取得できる - テストは
Mail::fake()とassertSent系で行う。assertSentOnce()は Laravel 13.31 以降
関連記事
- 【PHP】Laravel入門:インストールから簡単なサンプルアプリケーションの作成
- 【PHP】Laravelでテストを実装する方法
- 【PHP】Laravelでイベントとリスナーを実装する方法とその利用シーン(リスナーからメールを送る構成を組むときに)
- 【PHP】Laravelでタスクスケジューリングを実装する方法