메인 콘텐츠로 건너뛰기

Laravel 의 메일 기능이란

Laravel의 메일 기능은 Symfony Mailer를 베이스로 구축되어 있으며, SMTP·Mailgun·Postmark·Resend·Amazon SES·sendmail 등의 드라이버에 대응하고 있습니다.
이전 Laravel에서 사용되었던 SwiftMailer는 폐지되어 있습니다. Laravel 9 이후는 Symfony Mailer를 사용합니다.
메일 설정은 config/mail.php에서 관리합니다. .env 파일에서 사용할 드라이버를 전환할 수 있습니다.
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=your-username
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"

Mailable 클래스의 작성

Laravel에서는 애플리케이션이 전송하는 각 메일을 “Mailable” 클래스로 표현합니다. make:mail Artisan 명령어로 클래스를 생성합니다.
php artisan make:mail OrderShipped
생성된 클래스는 app/Mail/ 디렉터리에 배치됩니다.

Mailable 의 설정

생성된 Mailable 클래스에는 envelope(), content(), attachments()의 3가지 메서드가 있습니다.
<?php

namespace App\Mail;

use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct(
        public Order $order,
    ) {}

    public function envelope(): Envelope
    {
        return new Envelope(
            subject: '주문이 발송되었습니다',
        );
    }

    public function content(): Content
    {
        return new Content(
            view: 'mail.orders.shipped',
        );
    }

    public function attachments(): array
    {
        return [];
    }
}

송신자의 설정

envelope() 메서드로 송신자를 지정할 수 있습니다.
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;

public function envelope(): Envelope
{
    return new Envelope(
        from: new Address('[email protected]', 'Shop Support'),
        subject: '주문이 발송되었습니다',
    );
}
config/mail.php에 글로벌한 송신자 주소를 설정해 두면, 개별 Mailable에서의 지정을 생략할 수 있습니다.
'from' => [
    'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
    'name' => env('MAIL_FROM_NAME', 'Example'),
],

메일 본문의 설정

content() 메서드로 Blade 템플릿을 지정합니다. 생성자에서 public 프로퍼티에 설정한 데이터는 자동으로 템플릿에서 이용할 수 있습니다.
public function content(): Content
{
    return new Content(
        view: 'mail.orders.shipped',
    );
}
대응하는 Blade 템플릿(resources/views/mail/orders/shipped.blade.php)을 작성합니다.
<!DOCTYPE html>
<html>
<body>
    <h1>귀하의 주문이 발송되었습니다</h1>
    <p>주문 번호: {{ $order->id }}</p>
    <p>합계 금액: ¥{{ number_format($order->total) }}</p>
    <p>주문해 주셔서 감사합니다.</p>
</body>
</html>
데이터를 with 파라미터로 명시적으로 전달할 수도 있습니다. 이 경우는 프로퍼티를 protected 또는 private로 합니다.
public function __construct(
    protected Order $order,
) {}

public function content(): Content
{
    return new Content(
        view: 'mail.orders.shipped',
        with: [
            'orderId' => $this->order->id,
            'total' => $this->order->total,
        ],
    );
}

메일의 전송

Mail 파사드의 to() 메서드로 수신자를 지정하고, send()로 메일을 전송합니다.
<?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
{
    public function store(Request $request): RedirectResponse
    {
        $order = Order::findOrFail($request->order_id);

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

        return redirect('/orders');
    }
}
CC·BCC도 지정할 수 있습니다.
Mail::to($request->user())
    ->cc($ccUsers)
    ->bcc($bccUsers)
    ->send(new OrderShipped($order));
특정 메일러를 사용해 전송하려면 mailer() 메서드를 사용합니다.
Mail::mailer('postmark')
    ->to($request->user())
    ->send(new OrderShipped($order));

큐를 사용한 메일 전송

메일 전송은 응답 타임에 영향을 미치기 때문에, 큐를 사용해 백그라운드에서 전송하는 것을 권장합니다.
Mail::to($request->user())->queue(new OrderShipped($order));
큐를 사용하려면 사전에 큐의 설정과 워커의 기동이 필요합니다.
지연 전송도 가능합니다.
Mail::to($request->user())
    ->later(now()->plus(minutes: 10), new OrderShipped($order));
Mailable 클래스에 ShouldQueue를 구현하면, send()를 호출해도 항상 큐에 들어가게 됩니다.
use Illuminate\Contracts\Queue\ShouldQueue;

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

큐 접속과 큐 이름을 PHP 속성으로 지정

PHP 속성을 사용해 Mailable 클래스에 큐 접속과 큐 이름을 직접 지정할 수 있습니다. on()->queue() 메서드 체인 대신에 클래스 레벨에서 선언적으로 설정할 수 있습니다.
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;

#[Connection('sqs')]
#[Queue('emails')]
class OrderShipped extends Mailable implements ShouldQueue
{
    // ...
}
이 방법으로는 이 Mailable이 항상 SQS 접속의 emails 큐로 전송됨을 클래스 정의에서 명시할 수 있습니다.

Markdown Mail 의 작성

Markdown 형식의 메일을 사용하면 Laravel이 제공하는 아름다운 반응형 HTML 템플릿을 활용할 수 있습니다.

Markdown Mailable 의 생성

--markdown 옵션을 붙여 Mailable을 생성합니다.
php artisan make:mail OrderShipped --markdown=mail.orders.shipped
content() 메서드에서 markdown 파라미터를 사용합니다.
use Illuminate\Mail\Mailables\Content;

public function content(): Content
{
    return new Content(
        markdown: 'mail.orders.shipped',
        with: [
            'url' => route('orders.show', $this->order),
        ],
    );
}

Markdown 템플릿의 기술

Laravel이 제공하는 Blade 컴포넌트를 사용해 메일 본문을 작성합니다.
<x-mail::message>
# 귀하의 주문이 발송되었습니다

주문이 발송되었으므로 알려 드립니다.

<x-mail::button :url="$url">
주문을 확인하기
</x-mail::button>

이용해 주셔서 감사합니다.<br>
{{ config('app.name') }}
</x-mail::message>
이용 가능한 컴포넌트는 다음과 같습니다.
컴포넌트설명
<x-mail::button>버튼 링크(colorprimary·success·error를 지정 가능)
<x-mail::panel>눈에 띄는 패널 영역
<x-mail::table>Markdown 형식의 테이블
Markdown 메일은 동시에 플레인 텍스트 버전도 자동 생성됩니다. HTML 메일에 대응하지 않는 메일 클라이언트에서도 읽을 수 있습니다.

메일의 프리뷰

라우트에서 Mailable 인스턴스를 반환하면 브라우저에서 메일을 프리뷰할 수 있습니다. 개발 중의 확인에 편리합니다.
// routes/web.php
Route::get('/mailable', function () {
    $order = App\Models\Order::first();
    return new App\Mail\OrderShipped($order);
});

로컬 개발에서의 메일

운영 환경에서 메일을 잘못 전송하지 않도록, 로컬 개발에서는 Mailpit 등의 도구를 사용하면 편리합니다.
# .env (Mailpit)
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
Laragon이나 Laravel Herd에서는 Mailpit이 기본적으로 포함되어 있습니다.
log 드라이버를 사용하면 메일의 내용이 로그 파일에 기록됩니다. 메일 전송의 확인만이라면 가장 간편한 방법입니다.
MAIL_MAILER=log

정리

하고 싶은 것방법
Mailable을 작성php artisan make:mail ClassName
송신자를 설정envelope()from 파라미터
Blade 템플릿을 사용content()view 파라미터
Markdown 템플릿을 사용content()markdown 파라미터
메일을 전송Mail::to()->send()
큐로 전송Mail::to()->queue()
지연 전송Mail::to()->later()
마지막 수정일 2026년 7월 13일