알림

번역일: 2026년 7월 2일

알림

소개

Laravel은 이메일 전송 기능 외에도, 이메일·SMS·Slack 등 다양한 채널을 통한 알림 전송을 지원합니다. 또한 알림 내역을 데이터베이스에 저장해 웹 UI에서 표시하는 것도 가능합니다.

일반적으로 알림은 애플리케이션에서 발생한 어떤 사건을 사용자에게 간결하게 전달하는 메시지입니다. 예를 들어 결제 앱을 개발하고 있다면, "결제가 완료되었습니다"와 같은 알림을 이메일과 SMS 채널로 동시에 보낼 수 있습니다.

알림 생성

Laravel에서 알림은 app/Notifications 디렉터리에 클래스 하나로 표현됩니다. 프로젝트에 이 디렉터리가 없어도 걱정할 필요 없습니다. make:notification Artisan 명령을 실행하면 자동으로 생성됩니다.

php artisan make:notification InvoicePaid

이 명령을 실행하면 app/Notifications/InvoicePaid.php 파일이 생성됩니다. 생성된 클래스에는 via 메서드와 toMail, toArray 같은 메시지 빌드 메서드가 기본으로 포함되어 있습니다.

알림 전송

Notifiable 트레이트 사용

알림을 전송하는 방법은 두 가지입니다. 첫 번째는 Notifiable 트레이트의 notify 메서드를 사용하는 방법이고, 두 번째는 Notification 파사드를 사용하는 방법입니다.

Notifiable 트레이트는 기본적으로 App\Models\User 모델에 포함되어 있습니다.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; }

이 트레이트가 제공하는 notify 메서드는 알림 인스턴스를 인수로 받습니다.

use App\Notifications\InvoicePaid; $user->notify(new InvoicePaid($invoice));

NOTE

Notifiable 트레이트는 어떤 모델에도 추가할 수 있습니다. User 모델에만 한정되지 않습니다.

Notification 파사드 사용

Notification 파사드를 사용하면 여러 notifiable 엔티티(예: 사용자 컬렉션)에 알림을 한 번에 전송할 수 있습니다.

use Illuminate\Support\Facades\Notification; Notification::send($users, new InvoicePaid($invoice));

sendNow 메서드를 사용하면 알림이 ShouldQueue 인터페이스를 구현하더라도 즉시 전송됩니다.

Notification::sendNow($developers, new DeploymentCompleted($deployment));

전송 채널 지정

모든 알림 클래스에는 해당 알림이 어떤 채널로 전송될지 결정하는 via 메서드가 있습니다. Laravel은 기본적으로 mail, database, broadcast, vonage, slack 채널을 지원합니다.

NOTE

Telegram, Kakao 알림채널 등 다른 채널을 사용하고 싶다면 Laravel Notification Channels 웹사이트에서 커뮤니티 드라이버를 확인해 보세요.

via 메서드는 $notifiable 인스턴스를 받으므로, 수신자에 따라 채널을 다르게 지정하는 것도 가능합니다.

/** * 알림 전송 채널을 반환합니다. * * @return array<int, string> */ public function via(object $notifiable): array { return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database']; }

알림 큐 처리

WARNING

알림을 큐로 처리하기 전에 큐 설정을 완료하고 워커를 실행해야 합니다.

알림 전송은 외부 API 호출이 포함되거나 시간이 걸릴 수 있습니다. HTTP 응답 속도를 높이려면 알림을 큐에 넣어 비동기로 처리하는 것이 좋습니다. ShouldQueue 인터페이스와 Queueable 트레이트를 추가하면 됩니다. make:notification으로 생성한 클래스에는 이미 두 가지가 임포트되어 있으므로 바로 추가할 수 있습니다.

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; // ... }

ShouldQueue를 추가한 뒤에는 평소처럼 알림을 전송하면 됩니다. Laravel이 자동으로 큐에 넣어 처리합니다.

$user->notify(new InvoicePaid($invoice));

알림 전송을 특정 시간 이후로 지연하고 싶다면 delay 메서드를 체이닝할 수 있습니다.

$delay = now()->addMinutes(10); $user->notify((new InvoicePaid($invoice))->delay($delay));

채널별로 지연 시간을 다르게 설정하려면 배열을 전달합니다.

$user->notify((new InvoicePaid($invoice))->delay([ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10), ]));

알림을 큐에 넣을 때 각 수신자와 채널 조합마다 별도의 큐 Job이 생성됩니다. 예를 들어 수신자가 3명이고 채널이 2개라면 총 6개의 Job이 디스패치됩니다.

알림 큐 연결 커스터마이징

기본적으로 큐 알림은 애플리케이션의 기본 큐 연결을 사용합니다. 특정 알림에 다른 연결을 사용하려면 생성자에서 onConnection 메서드를 호출하거나, $connection 프로퍼티를 정의합니다.

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; public function __construct() { $this->onConnection('redis'); } }

채널별로 큐 연결을 지정하려면 viaConnections 메서드를 정의합니다.

/** * 채널별 큐 연결을 반환합니다. * * @return array<string, string> */ public function viaConnections(): array { return [ 'mail' => 'redis', 'database' => 'sync', ]; }

알림 큐 이름 커스터마이징

큐 이름을 지정하려면 $queue 프로퍼티를 정의하거나 생성자에서 onQueue 메서드를 호출합니다.

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; public function __construct() { $this->onQueue('notifications'); } }

채널별로 큐 이름을 다르게 지정하려면 viaQueues 메서드를 정의합니다.

/** * 채널별 큐 이름을 반환합니다. * * @return array<string, string> */ public function viaQueues(): array { return [ 'mail' => 'mail-queue', 'database' => 'db-queue', ]; }

큐 알림과 데이터베이스 트랜잭션

큐 알림이 데이터베이스 트랜잭션 내부에서 디스패치되면, 트랜잭션이 커밋되기 전에 큐 워커가 해당 Job을 처리할 수 있습니다. 이 경우 트랜잭션 중에 변경된 모델이나 레코드가 아직 데이터베이스에 반영되지 않은 상태일 수 있습니다. 또한 트랜잭션 내에서 생성된 모델이나 레코드가 DB에 존재하지 않을 수도 있습니다.

이를 방지하려면 알림 클래스에 $afterCommit 프로퍼티를 true로 설정합니다. 그러면 모든 열린 트랜잭션이 커밋된 후에 알림이 디스패치됩니다.

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; public bool $afterCommit = true; }

NOTE

이 문제에 대한 자세한 내용은 큐 Job과 데이터베이스 트랜잭션 문서를 참고하세요.

큐 알림 전송 여부 조건부 결정

런타임 조건에 따라 큐 알림을 전송할지 여부를 결정해야 할 때, shouldSend 메서드를 알림 클래스에 추가합니다. 이 메서드가 false를 반환하면 알림이 전송되지 않습니다.

/** * 알림을 전송할지 여부를 결정합니다. */ public function shouldSend(object $notifiable, string $channel): bool { return $this->invoice->isPaid(); }

즉석 알림

애플리케이션의 "사용자"가 아닌 임의의 대상(예: 외부 이메일 주소나 전화번호)에게 알림을 보내야 할 때가 있습니다. Notification 파사드의 route 메서드로 임시 notifiable 인스턴스를 만들어 전송할 수 있습니다.

use Illuminate\Broadcasting\Channel; use Illuminate\Support\Facades\Notification; Notification::route('mail', 'taylor@example.com') ->route('vonage', '5555555555') ->route('slack', '#slack-channel') ->route('broadcast', [new Channel('channel-name')]) ->notify(new InvoicePaid($invoice));

메일 채널로 즉석 알림을 보낼 때 수신자 이름도 지정하려면 이메일 주소를 키, 이름을 값으로 하는 배열을 전달합니다.

Notification::route('mail', ['barrett@example.com' => 'Barrett Blair']) ->notify(new InvoicePaid($invoice));

routes 메서드를 사용하면 여러 채널의 라우팅 정보를 한 번에 지정할 수 있습니다.

Notification::routes([ 'mail' => ['barrett@example.com' => 'Barrett Blair'], 'vonage' => '5555555555', ])->notify(new InvoicePaid($invoice));

메일 알림

메일 메시지 포맷팅

알림을 이메일로 전송하려면 알림 클래스에 toMail 메서드를 정의합니다. 이 메서드는 $notifiable 객체를 받아 Illuminate\Notifications\Messages\MailMessage 인스턴스를 반환해야 합니다.

MailMessage 클래스는 트랜잭션 이메일 메시지를 손쉽게 구성할 수 있는 몇 가지 메서드를 제공합니다. 메시지는 텍스트 줄과 "콜 투 액션(call to action)" 버튼으로 구성할 수 있습니다. 아래 예시를 보겠습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); return (new MailMessage) ->greeting('안녕하세요!') ->line('청구서 결제가 완료되었습니다.') ->lineIf($this->amount > 0, "결제 금액: {$this->amount}원") ->action('청구서 확인', $url) ->line('서비스를 이용해 주셔서 감사합니다!'); }

NOTE

toMail 메서드에서 $this->invoice->id를 사용하고 있습니다. 알림 생성자에 필요한 데이터를 자유롭게 주입할 수 있습니다.

위 예시에서는 인사말, 텍스트 줄, 콜 투 액션 버튼, 그리고 마지막 텍스트 줄을 등록합니다. MailMessage 객체가 제공하는 이 메서드들을 사용하면 간단한 트랜잭션 이메일을 빠르고 쉽게 포맷팅할 수 있습니다. 메일 채널은 메시지 컴포넌트를 보기 좋은 반응형 HTML 이메일 템플릿(플레인 텍스트 버전 포함)으로 변환합니다. 아래는 mail 채널로 생성되는 이메일 예시입니다.

NOTE

메일 알림을 보낼 때는 config/app.php 파일의 name 설정값을 적절히 지정해 두세요. 이 값이 이메일 헤더와 푸터에 사용됩니다.

다른 메일 알림 메서드

toMail 메서드에서 "줄(line)" 방식 대신 view 메서드를 사용해 커스텀 뷰 템플릿으로 이메일을 렌더링할 수도 있습니다.

오류 메시지

일부 알림은 사용자에게 오류(예: 결제 실패)를 알려야 합니다. 이 경우 error 메서드를 호출하면 콜 투 액션 버튼이 검은색 대신 빨간색으로 표시됩니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->error() ->subject('결제 실패 알림') ->line('결제 처리 중 문제가 발생했습니다.'); }

발신자 커스터마이징

기본적으로 이메일 발신자(From) 주소는 config/mail.php 설정 파일에서 가져옵니다. 특정 알림에만 다른 발신자를 사용하려면 from 메서드를 사용합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->from('barrett@example.com', 'Barrett Blair') ->line('...'); }

수신자 커스터마이징

mail 채널로 알림을 보낼 때 Laravel은 자동으로 notifiable 엔티티의 email 프로퍼티를 찾아 수신자로 사용합니다. 수신 이메일 주소를 커스터마이징하려면 notifiable 엔티티에 routeNotificationForMail 메서드를 정의합니다.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; class User extends Authenticatable { use Notifiable; /** * 메일 채널 알림 라우팅 주소를 반환합니다. * * @return array<string, string>|string */ public function routeNotificationForMail(Notification $notification): array|string { // 이메일 주소만 반환하는 경우 return $this->email_address; // 이메일 주소와 이름을 함께 반환하는 경우 return [$this->email_address => $this->name]; } }

제목 커스터마이징

기본적으로 이메일 제목은 알림 클래스 이름을 "Title Case"로 변환한 값입니다. 예를 들어 InvoicePaid 클래스라면 이메일 제목은 "Invoice Paid"가 됩니다. 제목을 직접 지정하려면 subject 메서드를 사용합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->subject('청구서 결제 완료') ->line('...'); }

메일러 커스터마이징

기본적으로 이메일 알림은 config/mail.php 설정 파일에 정의된 기본 메일러를 사용합니다. 런타임에 다른 메일러를 사용하려면 mailer 메서드를 호출합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->mailer('postmark') ->line('...'); }

템플릿 커스터마이징

메일 알림에 사용되는 HTML 및 플레인 텍스트 템플릿은 알림 패키지의 리소스를 퍼블리시하여 수정할 수 있습니다. 아래 명령을 실행하면 템플릿 파일이 resources/views/vendor/notifications 디렉터리에 복사됩니다.

php artisan vendor:publish --tag=laravel-notifications

첨부 파일

이메일에 파일을 첨부하려면 attach 메서드를 사용합니다. 첫 번째 인수로 파일의 절대 경로를 전달합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attach('/path/to/file'); }

NOTE

알림 메일 메시지의 attach 메서드는 첨부 가능 객체(attachable objects)도 지원합니다.

파일을 첨부할 때 두 번째 인수로 배열을 전달하면 표시 이름이나 MIME 타입을 지정할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attach('/path/to/file', [ 'as' => '청구서.pdf', 'mime' => 'application/pdf', ]); }

Mailable 객체에서 파일을 첨부하는 것과 달리, 알림에서는 attachFromStorage 메서드로 스토리지 디스크의 파일을 직접 첨부할 수 없습니다. 스토리지 디스크의 파일 절대 경로를 attach 메서드에 전달하거나, toMail 메서드에서 Mailable을 반환하는 방식을 사용하는 것이 좋습니다.

use App\Mail\InvoicePaid as InvoicePaidMailable; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email) ->attachFromStorage('/path/to/file'); }

여러 파일을 첨부해야 할 때는 attachMany 메서드를 사용합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attachMany([ '/path/to/forge.svg', '/path/to/vapor.svg' => [ 'as' => '증빙서류.svg', 'mime' => 'image/svg+xml', ], ]); }

원시 데이터 첨부

파일을 디스크에 저장하지 않고 메모리 상의 원시 바이트 문자열을 직접 첨부하려면 attachData 메서드를 사용합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attachData($this->pdf, '청구서.pdf', [ 'mime' => 'application/pdf', ]); }

태그 및 메타데이터 추가

Mailgun, Postmark 같은 서드파티 이메일 서비스는 메시지 "태그"와 "메타데이터"를 지원합니다. 이를 통해 애플리케이션이 보낸 이메일을 그룹화하고 추적할 수 있습니다. tagmetadata 메서드로 태그와 메타데이터를 추가할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->tag('결제완료') ->metadata('invoice_id', $this->invoice->id); }

Mailgun 드라이버를 사용하는 경우 태그메타데이터에 대한 자세한 내용은 Mailgun 공식 문서를 참고하세요. Postmark에 대한 내용은 태그메타데이터 문서를 참고하세요.

Amazon SES를 사용하는 경우 metadata 메서드로 SES "태그"를 메시지에 추가할 수 있습니다.

Symfony 메시지 커스터마이징

MailMessagewithSymfonyMessage 메서드를 사용하면 메시지 전송 전에 Symfony Message 인스턴스에 직접 접근하여 세부 설정을 조정할 수 있습니다.

use Symfony\Component\Mime\Email; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->withSymfonyMessage(function (Email $message) { $message->getHeaders()->addTextHeader( 'Custom-Header', '헤더 값' ); }); }

Mailable 사용

필요하다면 toMail 메서드에서 완전한 Mailable 객체를 반환할 수 있습니다. MailMessage 대신 Mailable을 반환할 때는 to 메서드로 수신자를 직접 지정해야 합니다.

use App\Mail\InvoicePaid as InvoicePaidMailable; use Illuminate\Mail\Mailable; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email); }

메일 알림 미리보기

메일 알림 템플릿을 디자인할 때 Blade 뷰처럼 브라우저에서 바로 렌더링 결과를 확인하면 편리합니다. 이를 위해 라우트 클로저나 컨트롤러에서 toMail 메서드가 반환하는 메일 메시지를 직접 반환할 수 있습니다. 브라우저에서 해당 라우트에 접근하면 이메일이 렌더링되어 표시됩니다.

use App\Models\Invoice; use App\Notifications\InvoicePaid; Route::get('/notification', function () { $invoice = Invoice::find(1); return (new InvoicePaid($invoice)) ->toMail($invoice->user); });

Markdown 메일 알림

Markdown 메일 알림을 사용하면 미리 만들어진 메일 알림 템플릿을 활용하면서도 길고 자유로운 커스텀 메시지를 작성할 수 있습니다. Markdown으로 메시지를 작성하면 Laravel이 아름다운 반응형 HTML 템플릿과 플레인 텍스트 버전을 자동으로 렌더링해줍니다.

메시지 생성

Markdown 템플릿이 포함된 알림을 생성하려면 make:notification Artisan 명령에 --markdown 옵션을 사용합니다.

php artisan make:notification InvoicePaid --markdown=mail.invoice.paid

다른 메일 알림과 마찬가지로 Markdown 템플릿을 사용하는 알림 클래스도 toMail 메서드를 정의해야 합니다. 단, lineaction 메서드 대신 markdown 메서드로 사용할 Markdown 템플릿 이름을 지정합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); return (new MailMessage) ->subject('청구서 결제 완료') ->markdown('mail.invoice.paid', ['url' => $url]); }

메시지 작성

Markdown 메일 알림은 Blade 컴포넌트와 Markdown 문법을 조합하여 사용합니다. Laravel에 내장된 알림 컴포넌트를 활용하면 멋진 이메일을 쉽게 만들 수 있습니다.

<x-mail::message> <h1 id="markdown-mail-notifications">결제 완료</h1> 청구서 결제가 완료되었습니다. <x-mail::button :url="$url"> 청구서 확인 </x-mail::button> 감사합니다,<br> {{ config('app.name') }} </x-mail::message>

버튼 컴포넌트

버튼 컴포넌트는 가운데 정렬된 버튼 링크를 렌더링합니다. url 속성과 선택적으로 color 속성을 받습니다. 지원하는 색상은 primary, green, red입니다. 버튼 컴포넌트는 메시지에 여러 개 추가할 수 있습니다.

<x-mail::button :url="$url" color="green"> 청구서 확인 </x-mail::button>

패널 컴포넌트

패널 컴포넌트는 나머지 메시지와 약간 다른 배경색의 패널 영역 안에 텍스트 블록을 렌더링합니다. 주의를 끌어야 하는 내용을 강조할 때 유용합니다.

<x-mail::panel> 여기에 패널 내용을 입력하세요. </x-mail::panel>

테이블 컴포넌트

테이블 컴포넌트를 사용하면 Markdown 테이블을 HTML 테이블로 변환할 수 있습니다. Markdown 표준 방식으로 정렬도 지원합니다.

<x-mail::table> | 상품 | 가격 | 수량 | | ----------- | -------: | -----: | | 라라벨 라이선스 | 150,000| 1 | | Forge 플랜 | 30,000| 1 | </x-mail::table>

컴포넌트 커스터마이징

Markdown 알림 컴포넌트를 직접 수정하려면 먼저 퍼블리시 명령으로 컴포넌트를 애플리케이션으로 내보냅니다.

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

이 명령을 실행하면 resources/views/vendor/mail 디렉터리에 컴포넌트 파일이 복사됩니다. mail 디렉터리에는 htmltext 디렉터리가 있으며, 각 컴포넌트의 HTML 버전과 플레인 텍스트 버전이 들어 있습니다. 이 파일들을 원하는 대로 수정할 수 있습니다.

CSS 커스터마이징

컴포넌트를 내보내면 resources/views/vendor/mail/html/themes 디렉터리에 default.css 파일이 생성됩니다. 이 파일의 CSS를 수정하면 스타일이 자동으로 HTML 이메일의 인라인 CSS로 변환됩니다.

Laravel Markdown 컴포넌트를 위한 완전히 새로운 테마를 만들고 싶다면, html/themes 디렉터리에 새 CSS 파일을 추가합니다. 파일을 저장한 후 config/mail.phptheme 옵션을 새 테마 이름으로 업데이트하세요.

특정 알림에만 커스텀 테마를 적용하려면 MailMessagetheme 메서드를 호출합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->theme('invoice') ->subject('청구서 결제 완료') ->markdown('mail.invoice.paid', ['url' => $url]); }

데이터베이스 알림

사전 준비

database 알림 채널은 알림 정보를 데이터베이스 테이블에 저장합니다. 이 테이블에는 알림 타입과 알림을 설명하는 JSON 데이터 구조가 포함됩니다.

저장된 알림은 애플리케이션 UI에서 조회하여 표시할 수 있습니다. 이를 위해 먼저 알림을 저장할 데이터베이스 테이블을 생성해야 합니다. make:notifications-table 명령으로 적절한 테이블 스키마를 가진 마이그레이션 파일을 생성할 수 있습니다.

php artisan make:notifications-tablephp artisan migrate

NOTE

notifiable 모델이 UUID 또는 ULID 기본 키를 사용한다면, 알림 테이블 마이그레이션의 morphs 메서드를 uuidMorphs 또는 ulidMorphs로 교체해야 합니다.

데이터베이스 알림 포맷팅

알림을 데이터베이스 테이블에 저장하려면 알림 클래스에 toDatabase 또는 toArray 메서드를 정의합니다. 이 메서드는 $notifiable 객체를 받아 순수 PHP 배열을 반환해야 합니다. 반환된 배열은 JSON으로 인코딩되어 notifications 테이블의 data 컬럼에 저장됩니다. 아래는 toArray 메서드 예시입니다.

/** * 알림의 배열 표현을 반환합니다. * * @return array<string, mixed> */ public function toArray(object $notifiable): array { return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]; }

알림이 애플리케이션의 데이터베이스에 저장되면 notifications 테이블의 type 컬럼에 알림 클래스 이름이 자동으로 설정됩니다. 이 값을 커스터마이징하려면 알림 클래스에 databaseType 메서드를 정의합니다.

/** * 알림의 데이터베이스 타입을 반환합니다. */ public function databaseType(object $notifiable): string { return 'invoice-paid'; }

`toDatabase` vs. `toArray`

toArray 메서드는 broadcast 채널에서도 JavaScript 프론트엔드로 브로드캐스트할 데이터를 결정하는 데 사용됩니다. database 채널과 broadcast 채널에 서로 다른 배열 표현이 필요하다면 toArray 대신 toDatabase 메서드를 별도로 정의하세요.

알림 조회

알림이 데이터베이스에 저장되면 notifiable 엔티티에서 편리하게 접근할 수 있어야 합니다. App\Models\User 모델에 기본 포함된 Notifiable 트레이트에는 notifications Eloquent 관계가 있어 엔티티의 알림을 가져올 수 있습니다. 다른 Eloquent 관계처럼 사용하면 됩니다. 기본적으로 알림은 created_at 타임스탬프 기준 최신순으로 정렬됩니다.

$user = App\Models\User::find(1); foreach ($user->notifications as $notification) { echo $notification->type; }

읽지 않은 알림만 가져오려면 unreadNotifications 관계를 사용합니다.

$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->type; }

NOTE

JavaScript 클라이언트에서 알림에 접근하려면 현재 사용자 등 notifiable 엔티티의 알림을 반환하는 알림 컨트롤러를 만들면 됩니다.

알림 읽음 처리

사용자가 알림을 확인하면 읽음 상태로 표시하는 것이 일반적입니다. Notifiable 트레이트는 알림 레코드의 read_at 컬럼을 업데이트하는 markAsRead 메서드를 제공합니다.

$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead(); }

알림을 하나씩 순회하는 대신 알림 컬렉션에서 직접 markAsRead 메서드를 호출할 수도 있습니다.

$user->unreadNotifications->markAsRead();

알림을 가져오지 않고 데이터베이스에서 일괄 업데이트하려면 대량 업데이트(mass-update) 쿼리를 사용할 수 있습니다.

$user = App\Models\User::find(1); $user->unreadNotifications()->update(['read_at' => now()]);

알림을 테이블에서 완전히 삭제하려면 delete 메서드를 사용합니다.

$user->notifications()->delete();

브로드캐스트 알림

사전 준비

브로드캐스트 알림을 사용하기 전에 Laravel의 이벤트 브로드캐스팅 서비스를 설정하고 숙지해야 합니다. 이벤트 브로드캐스팅을 통해 JavaScript 프론트엔드에서 서버 사이드 Laravel 이벤트에 실시간으로 반응할 수 있습니다.

브로드캐스트 알림 포맷팅

broadcast 채널은 Laravel의 이벤트 브로드캐스팅 서비스를 사용하여 알림을 실시간으로 JavaScript 프론트엔드에 전송합니다. 알림에서 브로드캐스팅을 지원하려면 toBroadcast 메서드를 정의합니다. 이 메서드는 $notifiable 객체를 받아 BroadcastMessage 인스턴스를 반환해야 합니다. toBroadcast 메서드가 없으면 toArray 메서드의 반환값이 브로드캐스팅 데이터로 사용됩니다. 반환된 데이터는 JSON으로 인코딩되어 JavaScript 프론트엔드로 전송됩니다. 아래는 toBroadcast 메서드 예시입니다.

use Illuminate\Notifications\Messages\BroadcastMessage; /** * 알림의 브로드캐스트 표현을 반환합니다. */ public function toBroadcast(object $notifiable): BroadcastMessage { return new BroadcastMessage([ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]); }

브로드캐스트 큐 설정

모든 브로드캐스트 알림은 큐에 넣어 처리됩니다. 브로드캐스트에 사용할 큐 연결이나 큐 이름을 설정하려면 BroadcastMessageonConnectiononQueue 메서드를 사용합니다.

return (new BroadcastMessage($data)) ->onConnection('sqs') ->onQueue('broadcasts');

알림 타입 커스터마이징

지정한 데이터 외에도 모든 브로드캐스트 알림에는 알림의 전체 클래스 이름이 담긴 type 필드가 자동으로 포함됩니다. 알림 type을 커스터마이징하려면 알림 클래스에 broadcastType 메서드를 정의합니다.

/** * 브로드캐스트할 알림 타입을 반환합니다. */ public function broadcastType(): string { return 'broadcast.message'; }

알림 수신 대기

알림은 {notifiable}.{id} 형식의 프라이빗 채널로 브로드캐스트됩니다. 예를 들어 ID가 1인 App\Models\User 인스턴스에 알림을 보내면 App.Models.User.1 채널로 브로드캐스트됩니다. Laravel Echo를 사용한다면 notification 메서드로 이 채널의 알림을 쉽게 수신할 수 있습니다.

Echo.private('App.Models.User.' + userId) .notification((notification) => { console.log(notification.type); });

알림 채널 커스터마이징

특정 notifiable 엔티티의 브로드캐스트 알림이 전송될 채널을 커스터마이징하려면 notifiable 모델에 receivesBroadcastNotificationsOn 메서드를 정의합니다.

<?php namespace App\Models; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * 사용자가 알림을 수신하는 채널을 반환합니다. */ public function receivesBroadcastNotificationsOn(): string { return 'users.'.$this->id; } }

SMS 알림

사전 준비

Laravel의 SMS 알림은 Vonage를 통해 전송됩니다. Vonage로 알림을 보내기 전에 laravel/vonage-notification-channelguzzlehttp/guzzle 패키지를 설치해야 합니다.

composer require laravel/vonage-notification-channel guzzlehttp/guzzle

패키지에는 설정 파일이 포함되어 있습니다. 하지만 이 설정 파일을 직접 애플리케이션으로 퍼블리시할 필요는 없습니다. VONAGE_KEYVONAGE_SECRET 환경 변수를 사용하여 Vonage 퍼블릭 키와 시크릿 키를 설정할 수 있습니다.

키를 설정한 후에는 VONAGE_SMS_FROM 환경 변수에 SMS 발신 기본 전화번호를 설정합니다. 이 전화번호는 Vonage 관리 콘솔에서 생성할 수 있습니다.

VONAGE_SMS_FROM=01012345678

SMS 알림 포맷팅

SMS로 알림을 전송하려면 알림 클래스에 toVonage 메서드를 정의합니다. 이 메서드는 $notifiable 객체를 받아 Illuminate\Notifications\Messages\VonageMessage 인스턴스를 반환합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * 알림의 Vonage/SMS 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('결제가 완료되었습니다!'); }

유니코드 콘텐츠

SMS 메시지에 유니코드 문자(한글 등)가 포함되는 경우 VonageMessage 인스턴스를 생성할 때 unicode 메서드를 호출해야 합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * 알림의 Vonage/SMS 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('결제가 완료되었습니다!') ->unicode(); }

발신 번호 커스터마이징

VONAGE_SMS_FROM 환경 변수에 설정된 번호와 다른 번호로 특정 알림을 보내려면 VonageMessage에서 from 메서드를 호출합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * 알림의 Vonage/SMS 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('결제가 완료되었습니다!') ->from('01087654321'); }

클라이언트 참조 추가

사용자, 팀 또는 클라이언트별 비용을 추적하려면 알림에 "클라이언트 참조(client reference)"를 추가할 수 있습니다. Vonage에서는 이 참조값으로 보고서를 생성하여 특정 고객의 SMS 사용 현황을 파악할 수 있습니다. 클라이언트 참조는 최대 40자의 임의 문자열입니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * 알림의 Vonage/SMS 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->clientReference((string) $notifiable->id) ->content('결제가 완료되었습니다!'); }

SMS 알림 라우팅

Vonage 알림을 올바른 전화번호로 라우팅하려면 notifiable 엔티티에 routeNotificationForVonage 메서드를 정의합니다.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; class User extends Authenticatable { use Notifiable; /** * Vonage 채널 알림 라우팅 번호를 반환합니다. */ public function routeNotificationForVonage(Notification $notification): string { return $this->phone_number; } }

Slack 알림

사전 준비

Slack 알림을 전송하기 전에 Composer로 Slack 알림 채널 패키지를 설치합니다.

composer require laravel/slack-notification-channel

추가로 Slack 워크스페이스에서 Slack 앱을 생성해야 합니다.

같은 워크스페이스 내 채널에만 알림을 보내는 경우, 앱에 chat:write, chat:write.public, chat:write.customize 스코프가 있어야 합니다. 이 스코프는 Slack의 "OAuth & Permissions" 앱 관리 탭에서 추가할 수 있습니다.

그 다음, 앱의 "Bot User OAuth Token"을 복사하여 애플리케이션의 services.php 설정 파일 내 slack 설정 배열에 추가합니다. 이 토큰은 Slack의 "OAuth & Permissions" 탭에서 확인할 수 있습니다.

'slack' => [ 'notifications' => [ 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), ], ],

앱 배포

외부 워크스페이스에 알림을 보내려면 Slack을 통해 앱을 배포해야 합니다. 앱 배포는 Slack 앱 관리 페이지에서 관리할 수 있습니다. 앱이 배포되면 즉석 알림을 사용하여 워크스페이스 사용자를 대신해 인증 토큰을 제공하는 방식으로 외부 워크스페이스에 알림을 전송할 수 있습니다.

Slack 알

알림

소개

Laravel은 이메일 발송 외에도 다양한 채널을 통한 알림 발송을 지원합니다. 이메일, SMS(Vonage 이용), Slack 등이 기본으로 제공되며, 커뮤니티에서 만든 다양한 알림 채널 패키지를 활용하면 수십 가지 채널로 알림을 보낼 수도 있습니다. 알림 내용을 데이터베이스에 저장해 웹 UI에서 표시하는 것도 가능합니다.

알림은 일반적으로 애플리케이션에서 발생한 사건을 사용자에게 간결하게 전달하는 짧은 메시지입니다. 예를 들어, 결제 관련 서비스를 개발 중이라면 "결제가 완료되었습니다"와 같은 알림을 이메일과 SMS로 동시에 발송할 수 있습니다.

알림

알림 생성하기

Laravel에서 각 알림은 하나의 클래스로 표현되며, 일반적으로 app/Notifications 디렉터리에 저장됩니다. 이 디렉터리가 프로젝트에 없더라도 걱정할 필요 없습니다. 아래 make:notification Artisan 명령어를 실행하면 자동으로 생성됩니다.

php artisan make:notification InvoicePaid

이 명령어를 실행하면 app/Notifications 디렉터리 안에 새 알림 클래스 파일이 생성됩니다. 각 알림 클래스에는 via 메서드와 하나 이상의 메시지 빌드 메서드(예: toMail, toDatabase)가 포함됩니다. 이 메서드들은 알림을 각 채널에 맞는 메시지 형태로 변환하는 역할을 합니다.

알림

알림 전송하기

Notifiable 트레이트 사용하기

알림을 전송하는 방법은 두 가지입니다. Notifiable 트레이트의 notify 메서드를 사용하는 방법과, Notification 파사드를 사용하는 방법입니다.

Notifiable 트레이트는 기본적으로 App\Models\User 모델에 포함되어 있습니다:

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; }

이 트레이트가 제공하는 notify 메서드는 알림 인스턴스를 인자로 받습니다:

use App\Notifications\InvoicePaid; $user->notify(new InvoicePaid($invoice));

NOTE

Notifiable 트레이트는 User 모델에만 사용할 수 있는 것이 아닙니다. 알림을 받아야 하는 어떤 모델에든 자유롭게 추가할 수 있습니다.

Notification 파사드 사용하기

여러 사용자에게 동시에 알림을 보내야 할 때는 Notification 파사드를 활용하는 것이 편리합니다. send 메서드에 알림을 받을 대상 컬렉션과 알림 인스턴스를 전달하면 됩니다:

use Illuminate\Support\Facades\Notification; Notification::send($users, new InvoicePaid($invoice));

알림을 즉시(큐 없이) 전송하고 싶다면 sendNow 메서드를 사용하세요. 알림 클래스가 ShouldQueue 인터페이스를 구현하고 있더라도 즉시 발송됩니다:

Notification::sendNow($developers, new DeploymentCompleted($deployment));

전송 채널 지정하기

알림 클래스의 via 메서드에서 알림을 어떤 채널로 전달할지 결정합니다. 기본적으로 mail, database, broadcast, vonage, slack 채널을 지원합니다.

NOTE

Telegram, Pusher 등 다른 채널을 사용하고 싶다면 커뮤니티 기반의 Laravel Notification Channels 사이트를 확인하세요.

via 메서드는 $notifiable 인스턴스를 인자로 받습니다. 이를 활용하면 수신 대상에 따라 채널을 동적으로 결정할 수 있습니다:

/** * 알림 전송 채널을 반환합니다. * * @return array<int, string> */ public function via(object $notifiable): array { return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database']; }

알림 큐 처리하기

WARNING

알림을 큐에 넣기 전에 반드시 큐를 설정하고 워커를 실행해야 합니다.

외부 API를 호출하는 채널(예: 메일, SMS)을 통해 알림을 보내면 응답이 느려질 수 있습니다. 이럴 때는 알림 클래스에 ShouldQueue 인터페이스와 Queueable 트레이트를 추가하면 알림이 백그라운드에서 처리됩니다. make:notification 명령으로 생성된 알림 클래스에는 이미 두 가지가 임포트되어 있으므로 바로 추가할 수 있습니다:

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; // ... }

ShouldQueue 인터페이스를 추가한 후에도 알림 전송 방식은 동일합니다. Laravel이 인터페이스를 감지하여 자동으로 큐에 넣어 처리합니다:

$user->notify(new InvoicePaid($invoice));

큐에 넣을 때는 수신자와 채널의 조합마다 별도의 Job이 생성됩니다. 예를 들어 수신자 3명, 채널 2개라면 총 6개의 Job이 큐에 등록됩니다.

알림 전송 지연하기

알림을 일정 시간 뒤에 전송하고 싶다면 delay 메서드를 체이닝하세요:

$delay = now()->addMinutes(10); $user->notify((new InvoicePaid($invoice))->delay($delay));

채널별 전송 지연 설정하기

채널마다 다른 지연 시간을 설정하려면 delay 메서드에 배열을 전달하세요:

$user->notify((new InvoicePaid($invoice))->delay([ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10), ]));

또는 알림 클래스 내부에 withDelay 메서드를 정의해도 됩니다. 이 메서드는 채널 이름과 지연 시간을 담은 배열을 반환해야 합니다:

/** * 채널별 전송 지연 시간을 반환합니다. * * @return array<string, \Illuminate\Support\Carbon> */ public function withDelay(object $notifiable): array { return [ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10), ]; }

알림 큐 커넥션 지정하기

기본적으로 큐 알림은 애플리케이션의 기본 큐 커넥션을 사용합니다. 특정 알림에 다른 커넥션을 사용하려면 생성자에서 onConnection 메서드를 호출하세요:

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; /** * 새 알림 인스턴스를 생성합니다. */ public function __construct() { $this->onConnection('redis'); } }

채널마다 다른 큐 커넥션을 사용하고 싶다면 viaConnections 메서드를 정의하세요. 채널 이름과 커넥션 이름의 쌍으로 이루어진 배열을 반환합니다:

/** * 채널별 큐 커넥션을 반환합니다. * * @return array<string, string> */ public function viaConnections(): array { return [ 'mail' => 'redis', 'database' => 'sync', ]; }

채널별 큐 이름 지정하기

채널마다 다른 큐를 사용하고 싶다면 viaQueues 메서드를 정의하세요. 채널 이름과 큐 이름의 쌍으로 이루어진 배열을 반환합니다:

/** * 채널별 큐 이름을 반환합니다. * * @return array<string, string> */ public function viaQueues(): array { return [ 'mail' => 'mail-queue', 'slack' => 'slack-queue', ]; }

큐 알림과 데이터베이스 트랜잭션

데이터베이스 트랜잭션 내에서 큐 알림을 디스패치하면, 트랜잭션이 커밋되기 전에 큐 워커가 알림을 처리할 수 있습니다. 이 경우 트랜잭션 내에서 변경하거나 생성한 데이터가 아직 데이터베이스에 반영되지 않아 알림 처리 중 예기치 않은 오류가 발생할 수 있습니다.

큐 커넥션의 after_commit 설정이 false인 경우에도, 특정 알림이 열린 트랜잭션이 모두 커밋된 후 전송되도록 하려면 알림을 보낼 때 afterCommit 메서드를 호출하세요:

use App\Notifications\InvoicePaid; $user->notify((new InvoicePaid($invoice))->afterCommit());

또는 생성자에서 호출할 수도 있습니다:

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue { use Queueable; /** * 새 알림 인스턴스를 생성합니다. */ public function __construct() { $this->afterCommit(); } }

NOTE

이 문제를 해결하는 방법에 대한 자세한 내용은 큐 Job과 데이터베이스 트랜잭션 문서를 참고하세요.

큐 알림 최종 전송 여부 결정하기

큐 워커가 알림을 처리하는 시점에 전송 여부를 최종적으로 결정하고 싶다면 알림 클래스에 shouldSend 메서드를 정의하세요. 이 메서드가 false를 반환하면 알림이 전송되지 않습니다:

/** * 알림을 전송할지 여부를 결정합니다. */ public function shouldSend(object $notifiable, string $channel): bool { return $this->invoice->isPaid(); }

온디맨드 알림

애플리케이션에 사용자로 등록되지 않은 외부 대상에게 알림을 보내야 할 때가 있습니다. 예를 들어 회원 가입 전 이메일 인증을 하거나, 임시로 생성된 연락처에 발송하는 경우가 이에 해당합니다. 이럴 때는 Notification 파사드의 route 메서드로 알림 라우팅 정보를 직접 지정할 수 있습니다:

use Illuminate\Broadcasting\Channel; use Illuminate\Support\Facades\Notification; Notification::route('mail', 'taylor@example.com') ->route('vonage', '5555555555') ->route('slack', '#slack-channel') ->route('broadcast', [new Channel('channel-name')]) ->notify(new InvoicePaid($invoice));

mail 채널로 온디맨드 알림을 보낼 때 수신자 이름도 함께 지정하려면, 이메일 주소를 키로, 이름을 값으로 하는 배열을 전달하세요:

Notification::route('mail', [ 'barrett@example.com' => 'Barrett Blair', ])->notify(new InvoicePaid($invoice));

routes 메서드를 사용하면 여러 채널의 라우팅 정보를 한 번에 지정할 수 있습니다:

Notification::routes([ 'mail' => ['barrett@example.com' => 'Barrett Blair'], 'vonage' => '5555555555', ])->notify(new InvoicePaid($invoice));

메일 알림

메일 메시지 포맷팅

알림을 이메일로 전송하려면 알림 클래스에 toMail 메서드를 정의해야 합니다. 이 메서드는 $notifiable 엔티티를 인자로 받아 Illuminate\Notifications\Messages\MailMessage 인스턴스를 반환해야 합니다.

MailMessage 클래스는 트랜잭션 이메일을 손쉽게 구성할 수 있는 간단한 메서드들을 제공합니다. 텍스트 라인과 "행동 유도(call to action)" 버튼을 조합해 메시지를 만들 수 있습니다. 아래는 toMail 메서드의 예시입니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); return (new MailMessage) ->greeting('안녕하세요!') ->line('청구서 결제가 완료되었습니다!') ->lineIf($this->amount > 0, "결제 금액: {$this->amount}원") ->action('청구서 확인하기', $url) ->line('저희 서비스를 이용해 주셔서 감사합니다!'); }

NOTE

toMail 메서드 내에서 $this->invoice->id와 같이 인스턴스 프로퍼티를 활용하고 있습니다. 알림 메시지 생성에 필요한 데이터는 알림 클래스의 생성자를 통해 전달하면 됩니다.

위 예시에서는 인사말, 텍스트 라인, 행동 유도 버튼, 그리고 마무리 텍스트 라인을 순서대로 등록합니다. MailMessage가 제공하는 이 메서드들 덕분에 트랜잭션 이메일을 빠르고 간편하게 구성할 수 있습니다. 메일 채널은 이 구성 요소들을 반응형 HTML 이메일 템플릿과 플레인 텍스트 형식으로 자동 변환합니다. 결과 이메일은 아래와 같은 모습입니다.

NOTE

메일 알림을 발송하기 전에, config/app.phpname 옵션이 올바르게 설정되어 있는지 확인하세요. 이 값은 메일 알림 메시지의 헤더와 푸터에 사용됩니다.

오류 메시지

결제 실패와 같이 오류 상황을 사용자에게 알려야 할 때는, 메시지를 빌드할 때 error 메서드를 호출하세요. error 메서드를 사용하면 행동 유도 버튼이 검정색 대신 빨간색으로 표시됩니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->error() ->subject('청구서 결제 실패') ->line('...'); }

기타 메일 알림 포맷팅 옵션

알림 클래스 내에서 텍스트 라인을 직접 정의하는 대신, view 메서드를 사용해 알림 이메일 렌더링에 사용할 커스텀 템플릿을 지정할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage)->view( 'mail.invoice.paid', ['invoice' => $this->invoice] ); }

view 메서드에 배열을 전달하면, 배열의 두 번째 요소로 플레인 텍스트 뷰를 지정할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage)->view( ['mail.invoice.paid', 'mail.invoice.paid-text'], ['invoice' => $this->invoice] ); }

메시지가 플레인 텍스트만으로 구성된다면 text 메서드를 사용할 수도 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage)->text( 'mail.invoice.paid-text', ['invoice' => $this->invoice] ); }

발신자 커스터마이징

기본적으로 이메일의 발신자(from) 주소는 config/mail.php 설정 파일에서 정의됩니다. 특정 알림에 대해 발신자 주소를 별도로 지정하고 싶다면 from 메서드를 사용하세요.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->from('no-reply@example.com', '서비스 알림') ->line('...'); }

수신자 커스터마이징

mail 채널로 알림을 전송할 때, 알림 시스템은 notifiable 엔티티의 email 프로퍼티를 자동으로 찾아 사용합니다. 수신 이메일 주소를 직접 제어하고 싶다면, notifiable 엔티티에 routeNotificationForMail 메서드를 정의하세요.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; class User extends Authenticatable { use Notifiable; /** * 메일 채널의 알림 라우팅 주소를 반환합니다. * * @return array<string, string>|string */ public function routeNotificationForMail(Notification $notification): array|string { // 이메일 주소만 반환... return $this->email_address; // 이메일 주소와 이름을 함께 반환... return [$this->email_address => $this->name]; } }

제목 커스터마이징

이메일 제목은 기본적으로 알림 클래스명을 "Title Case" 형식으로 변환하여 사용합니다. 예를 들어, 클래스명이 InvoicePaid라면 제목은 Invoice Paid가 됩니다. 제목을 직접 지정하려면 메시지를 빌드할 때 subject 메서드를 호출하세요.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->subject('알림 제목') ->line('...'); }

메일러 커스터마이징

기본적으로 메일 알림은 config/mail.php에 정의된 기본 메일러를 사용합니다. 특정 알림에 대해 다른 메일러를 사용하려면 메시지를 빌드할 때 mailer 메서드를 호출하세요.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->mailer('postmark') ->line('...'); }

템플릿 커스터마이징

메일 알림에 사용되는 HTML 및 플레인 텍스트 템플릿을 수정하려면, 아래 명령어로 알림 패키지의 리소스를 퍼블리시하세요. 퍼블리시 후 템플릿 파일은 resources/views/vendor/notifications 디렉토리에 위치합니다.

php artisan vendor:publish --tag=laravel-notifications

첨부 파일

메일 알림에 파일을 첨부하려면 attach 메서드를 사용하세요. 첫 번째 인자로 파일의 절대 경로를 전달합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attach('/path/to/file'); }

NOTE

알림 메일 메시지의 attach 메서드는 첨부 가능한 객체(attachable objects)도 지원합니다. 자세한 내용은 첨부 가능한 객체 문서를 참고하세요.

파일 첨부 시 두 번째 인자로 배열을 전달하면 표시 이름과 MIME 타입을 함께 지정할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attach('/path/to/file', [ 'as' => 'name.pdf', 'mime' => 'application/pdf', ]); }

Mailable 객체와 달리, 알림 메일 메시지에서는 attachFromStorage로 스토리지 디스크에서 직접 파일을 첨부할 수 없습니다. 스토리지 디스크의 파일을 첨부하려면 해당 파일의 절대 경로를 attach 메서드에 전달하거나, toMail 메서드에서 Mailable 객체를 반환하는 방법을 사용하세요.

use App\Mail\InvoicePaid as InvoicePaidMailable; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email) ->attachFromStorage('/path/to/file'); }

여러 파일을 한 번에 첨부해야 한다면 attachMany 메서드를 사용하세요.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attachMany([ '/path/to/logo.svg', '/path/to/brochure.svg' => [ 'as' => '안내문.svg', 'mime' => 'image/svg+xml', ], ]); }

원시 데이터 첨부

바이트 문자열 형태의 데이터를 첨부 파일로 추가하려면 attachData 메서드를 사용하세요. 첨부 파일에 부여할 파일명도 함께 지정해야 합니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('안녕하세요!') ->attachData($this->pdf, 'invoice.pdf', [ 'mime' => 'application/pdf', ]); }

태그 및 메타데이터 추가

Mailgun, Postmark와 같은 일부 서드파티 이메일 서비스는 메시지 "태그"와 "메타데이터"를 지원하며, 이를 통해 발송된 이메일을 그룹화하고 추적할 수 있습니다. tagmetadata 메서드를 사용해 메일 메시지에 태그와 메타데이터를 추가할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('댓글에 추천이 달렸습니다!') ->tag('upvote') ->metadata('comment_id', $this->comment->id); }

Mailgun 드라이버를 사용 중이라면 태그메타데이터에 관한 Mailgun 공식 문서를 참고하세요. Postmark를 사용한다면 태그메타데이터에 관한 Postmark 문서를 참고하세요.

Amazon SES로 이메일을 발송하는 경우에는 metadata 메서드를 사용해 SES "태그"를 메시지에 첨부하세요.

Symfony 메시지 커스터마이징

MailMessage 클래스의 withSymfonyMessage 메서드를 사용하면, 메시지 전송 전에 Symfony Message 인스턴스를 직접 조작할 수 있습니다. 이를 통해 메시지를 보다 세밀하게 커스터마이징할 수 있습니다.

use Symfony\Component\Mime\Email; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->withSymfonyMessage(function (Email $message) { $message->getHeaders()->addTextHeader( 'Custom-Header', 'Header Value' ); }); }

Mailable 사용

필요한 경우, toMail 메서드에서 완전한 Mailable 객체를 반환할 수 있습니다. MailMessage 대신 Mailable을 반환할 때는 Mailable 객체의 to 메서드로 수신자를 직접 지정해야 합니다.

use App\Mail\InvoicePaid as InvoicePaidMailable; use Illuminate\Mail\Mailable; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email); }

Mailable과 온디맨드 알림

온디맨드 알림을 발송하는 경우, toMail 메서드에 전달되는 $notifiable 인스턴스는 Illuminate\Notifications\AnonymousNotifiable의 인스턴스입니다. 이 클래스의 routeNotificationFor 메서드를 사용하면 알림을 발송할 이메일 주소를 조회할 수 있습니다.

use App\Mail\InvoicePaid as InvoicePaidMailable; use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Mail\Mailable; /** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): Mailable { $address = $notifiable instanceof AnonymousNotifiable ? $notifiable->routeNotificationFor('mail') : $notifiable->email; return (new InvoicePaidMailable($this->invoice)) ->to($address); }

메일 알림 미리보기

메일 알림 템플릿을 설계할 때, 실제 이메일을 발송하지 않고도 브라우저에서 렌더링 결과를 바로 확인하면 편리합니다. Laravel은 라우트 클로저나 컨트롤러에서 MailMessage를 직접 반환하는 방식으로 이를 지원합니다. 반환된 MailMessage는 브라우저에 바로 렌더링되어 표시됩니다.

use App\Models\Invoice; use App\Notifications\InvoicePaid; Route::get('/notification', function () { $invoice = Invoice::find(1); return (new InvoicePaid($invoice)) ->toMail($invoice->user); });

알림

Markdown 메일 알림

Markdown 메일 알림을 사용하면 Laravel이 제공하는 사전 제작된 메일 템플릿을 활용하면서도, 더 길고 풍부한 메시지를 자유롭게 작성할 수 있습니다. Markdown으로 메시지를 작성하면 Laravel이 아름답고 반응형인 HTML 템플릿으로 자동 렌더링하며, 동시에 일반 텍스트 버전도 함께 생성합니다.

메시지 생성하기

Markdown 템플릿을 사용하는 알림 클래스를 생성하려면 make:notification Artisan 명령어에 --markdown 옵션을 추가합니다:

php artisan make:notification InvoicePaid --markdown=mail.invoice.paid

일반 메일 알림과 마찬가지로, Markdown 템플릿을 사용하는 알림 클래스에도 toMail 메서드를 정의해야 합니다. 단, line이나 action 메서드 대신 markdown 메서드로 사용할 Markdown 템플릿 이름을 지정합니다. 템플릿에 전달할 데이터는 두 번째 인자로 배열 형태로 넘깁니다:

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); return (new MailMessage) ->subject('청구서 결제 완료') ->markdown('mail.invoice.paid', ['url' => $url]); }

메시지 작성하기

Markdown 메일 알림은 Blade 컴포넌트와 Markdown 문법을 함께 사용합니다. Laravel이 제공하는 알림 전용 컴포넌트를 활용해 손쉽게 메시지를 구성할 수 있습니다:

<x-mail::message> # 청구서 결제 완료 청구서 결제가 완료되었습니다! <x-mail::button :url="$url"> 청구서 확인하기 </x-mail::button> 감사합니다,<br> {{ config('app.name') }} </x-mail::message>

Button 컴포넌트

Button 컴포넌트는 가운데 정렬된 버튼 링크를 렌더링합니다. url과 선택적인 color 두 가지 인자를 받으며, 사용 가능한 색상은 primary, green, red입니다. 하나의 알림에 버튼을 여러 개 추가할 수도 있습니다:

<x-mail::button :url="$url" color="green"> 청구서 확인하기 </x-mail::button>

Panel 컴포넌트

Panel 컴포넌트는 본문과 약간 다른 배경색의 패널 영역 안에 텍스트 블록을 렌더링합니다. 특정 내용을 시각적으로 강조하고 싶을 때 유용합니다:

<x-mail::panel> 이 부분이 패널 안에 표시되는 내용입니다. </x-mail::panel>

Table 컴포넌트

Table 컴포넌트는 Markdown 테이블을 HTML 테이블로 변환합니다. 컴포넌트의 내용으로 Markdown 테이블 문법을 그대로 사용하면 되며, 기본 Markdown 테이블 정렬 문법(:---, :---:, ---:)도 지원합니다:

<x-mail::table> | 상품명 | 수량 | 금액 | | ------------- |:-------------:| --------:| | 라라벨 강의 | 1 |10,000 | | 호스팅 1개월 | 1 |20,000 | </x-mail::table>

컴포넌트 커스터마이징

Markdown 알림 컴포넌트를 애플리케이션 내부로 내보내서 자유롭게 수정할 수 있습니다. vendor:publish Artisan 명령어에 laravel-mail 태그를 지정하면 됩니다:

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

이 명령어를 실행하면 Markdown 메일 컴포넌트가 resources/views/vendor/mail 디렉터리에 복사됩니다. 해당 디렉터리 안에는 htmltext 디렉터리가 생성되며, 각각 HTML 버전과 텍스트 버전의 컴포넌트 파일이 들어 있습니다. 이 파일들을 원하는 대로 수정해서 사용하면 됩니다.

CSS 커스터마이징

컴포넌트를 내보내고 나면 resources/views/vendor/mail/html/themes 디렉터리 안에 default.css 파일이 생성됩니다. 이 파일의 CSS를 수정하면 변경 사항이 Markdown 알림의 HTML 렌더링 결과에 자동으로 인라인 스타일로 반영됩니다.

Laravel Markdown 컴포넌트에 완전히 새로운 테마를 적용하고 싶다면, html/themes 디렉터리에 새 CSS 파일을 추가하면 됩니다. 파일명을 저장한 뒤 config/mail.php 설정 파일의 theme 옵션을 새 테마 파일명으로 변경하면 됩니다.

특정 알림 하나에만 별도 테마를 적용하려면, 알림 메시지를 구성할 때 theme 메서드를 호출하면 됩니다. theme 메서드에는 해당 알림 전송 시 사용할 테마 이름을 전달합니다:

/** * 알림의 메일 표현을 반환합니다. */ public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->theme('invoice') ->subject('청구서 결제 완료') ->markdown('mail.invoice.paid', ['url' => $url]); }

데이터베이스 알림

사전 준비

database 알림 채널은 알림 정보를 데이터베이스 테이블에 저장합니다. 이 테이블에는 알림 타입과 알림 내용을 나타내는 JSON 데이터 구조 등이 함께 저장됩니다.

저장된 데이터는 애플리케이션의 UI에서 조회하여 표시할 수 있습니다. 단, 그 전에 알림을 저장할 테이블을 먼저 생성해야 합니다. notifications:table 명령어를 실행하면 적절한 스키마가 포함된 마이그레이션 파일이 생성됩니다.

php artisan notifications:tablephp artisan migrate

NOTE

Notifiable 모델이 UUID 또는 ULID 기본 키를 사용하는 경우, 알림 테이블 마이그레이션에서 morphs 메서드를 uuidMorphs 또는 ulidMorphs로 교체해야 합니다.

데이터베이스 알림 포맷 지정

알림을 데이터베이스에 저장하려면 알림 클래스에 toDatabase 또는 toArray 메서드를 정의해야 합니다. 이 메서드는 $notifiable 엔티티를 인자로 받아 순수 PHP 배열을 반환합니다. 반환된 배열은 JSON으로 인코딩되어 notifications 테이블의 data 컬럼에 저장됩니다. 아래는 toArray 메서드의 예시입니다.

/** * 알림의 배열 표현을 반환합니다. * * @return array<string, mixed> */ public function toArray(object $notifiable): array { return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]; }

알림이 데이터베이스에 저장될 때, type 컬럼에는 알림 클래스의 전체 이름이 자동으로 저장됩니다. 이 동작을 변경하고 싶다면 알림 클래스에 databaseType 메서드를 정의하면 됩니다.

/** * 알림의 데이터베이스 타입을 반환합니다. * * @return string */ public function databaseType(object $notifiable): string { return 'invoice-paid'; }

toDatabase vs. toArray

toArray 메서드는 broadcast 채널에서도 사용됩니다. JavaScript 프런트엔드로 브로드캐스트할 데이터를 결정할 때도 이 메서드가 호출되기 때문입니다. databasebroadcast 채널에 서로 다른 데이터를 제공하고 싶다면, toArray 대신 toDatabase 메서드를 별도로 정의하세요. toDatabase가 정의된 경우 데이터베이스 저장에는 이 메서드가, 브로드캐스트에는 toArray가 각각 사용됩니다.

알림 조회

알림이 데이터베이스에 저장되면, notifiable 엔티티에서 이를 편리하게 조회할 수 있어야 합니다. Laravel의 기본 App\Models\User 모델에 포함된 Illuminate\Notifications\Notifiable 트레이트에는 해당 엔티티의 알림을 반환하는 notifications Eloquent 관계가 포함되어 있습니다. 다른 Eloquent 관계와 동일한 방식으로 접근하면 됩니다. 기본적으로 알림은 created_at 기준으로 내림차순 정렬되어 최신 알림이 앞에 옵니다.

$user = App\Models\User::find(1); foreach ($user->notifications as $notification) { echo $notification->type; }

읽지 않은 알림만 조회하려면 unreadNotifications 관계를 사용하세요. 마찬가지로 created_at 기준 내림차순으로 정렬됩니다.

$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->type; }

NOTE

JavaScript 클라이언트에서 알림 데이터를 조회하려면, 현재 사용자와 같은 notifiable 엔티티의 알림을 반환하는 알림 컨트롤러를 별도로 만들고, JavaScript에서 해당 컨트롤러 URL로 HTTP 요청을 보내는 방식을 사용하세요.

알림을 읽음으로 표시

사용자가 알림을 확인했을 때 해당 알림을 "읽음" 상태로 변경하는 것이 일반적입니다. Illuminate\Notifications\Notifiable 트레이트가 제공하는 markAsRead 메서드를 사용하면 알림 레코드의 read_at 컬럼이 갱신됩니다.

$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead(); }

루프를 사용하지 않고, 알림 컬렉션에 직접 markAsRead를 호출할 수도 있습니다.

$user->unreadNotifications->markAsRead();

데이터베이스에서 알림을 가져오지 않고 일괄 업데이트 쿼리로 모든 알림을 읽음 처리할 수도 있습니다.

$user = App\Models\User::find(1); $user->unreadNotifications()->update(['read_at' => now()]);

알림을 테이블에서 완전히 삭제하려면 delete를 사용하세요.

$user->notifications()->delete();

브로드캐스트 알림

사전 준비

브로드캐스트 알림을 사용하기 전에, Laravel의 이벤트 브로드캐스팅 서비스를 설정하고 기본 개념을 익혀두어야 합니다. 이벤트 브로드캐스팅은 서버 측에서 발생한 Laravel 이벤트를 JavaScript 프론트엔드에서 실시간으로 수신할 수 있게 해주는 기능입니다.

브로드캐스트 알림 포맷 정의

broadcast 채널은 Laravel의 이벤트 브로드캐스팅 서비스를 통해 알림을 전송하며, JavaScript 프론트엔드에서 실시간으로 알림을 수신할 수 있습니다.

알림 클래스에 toBroadcast 메서드를 정의하면 브로드캐스트 형식을 직접 지정할 수 있습니다. 이 메서드는 $notifiable 인스턴스를 인자로 받아 BroadcastMessage 인스턴스를 반환해야 합니다. toBroadcast 메서드가 없는 경우에는 toArray 메서드의 반환값이 브로드캐스트 데이터로 사용됩니다. 반환된 데이터는 JSON으로 인코딩되어 프론트엔드로 전송됩니다.

use Illuminate\Notifications\Messages\BroadcastMessage; /** * 브로드캐스트 알림 데이터를 반환합니다. */ public function toBroadcast(object $notifiable): BroadcastMessage { return new BroadcastMessage([ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]); }

브로드캐스트 큐 설정

브로드캐스트 알림은 모두 큐를 통해 처리됩니다. 브로드캐스트 작업에 사용할 큐 커넥션이나 큐 이름을 변경하려면 BroadcastMessageonConnectiononQueue 메서드를 사용하세요.

return (new BroadcastMessage($data)) ->onConnection('sqs') ->onQueue('broadcasts');

알림 타입 커스터마이징

브로드캐스트 알림에는 지정한 데이터 외에도, 알림 클래스의 전체 클래스명이 담긴 type 필드가 자동으로 포함됩니다. 이 값을 직접 지정하려면 알림 클래스에 broadcastType 메서드를 정의하세요.

/** * 브로드캐스트 알림의 타입을 반환합니다. */ public function broadcastType(): string { return 'broadcast.message'; }

알림 수신 대기

알림은 {notifiable}.{id} 형식의 프라이빗 채널로 브로드캐스트됩니다. 예를 들어 ID가 1App\Models\User 인스턴스에 알림을 보내면, App.Models.User.1 프라이빗 채널로 브로드캐스트됩니다. Laravel Echo를 사용하면 notification 메서드로 해당 채널의 알림을 간편하게 수신할 수 있습니다.

Echo.private('App.Models.User.' + userId) .notification((notification) => { console.log(notification.type); });

알림 채널 커스터마이징

특정 엔티티의 브로드캐스트 알림이 전송될 채널을 변경하고 싶다면, notifiable 엔티티(예: User 모델)에 receivesBroadcastNotificationsOn 메서드를 정의하세요.

<?php namespace App\Models; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * 사용자가 브로드캐스트 알림을 수신할 채널을 반환합니다. */ public function receivesBroadcastNotificationsOn(): string { return 'users.'.$this->id; } }

NOTE

채널명을 커스터마이징한 경우, 프론트엔드의 Echo 수신 코드에서도 동일한 채널명을 사용해야 합니다.

알림

SMS 알림

사전 준비

Laravel에서 SMS 알림 전송은 Vonage(구 Nexmo)를 통해 이루어집니다. Vonage로 알림을 보내려면 먼저 아래 패키지를 설치해야 합니다.

composer require laravel/vonage-notification-channel guzzlehttp/guzzle

이 패키지에는 설정 파일이 포함되어 있지만, 반드시 애플리케이션에 내보낼 필요는 없습니다. 아래와 같이 환경 변수만 설정하면 됩니다.

VONAGE_KEY=your-public-key VONAGE_SECRET=your-secret-key

키를 설정한 후, SMS를 발송할 기본 발신 번호를 VONAGE_SMS_FROM 환경 변수로 지정합니다. 이 번호는 Vonage 콘솔에서 생성할 수 있습니다.

VONAGE_SMS_FROM=15556666666

SMS 알림 포맷 정의

알림 클래스가 SMS 전송을 지원하려면 toVonage 메서드를 정의해야 합니다. 이 메서드는 $notifiable 엔티티를 인수로 받고, Illuminate\Notifications\Messages\VonageMessage 인스턴스를 반환해야 합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * Vonage / SMS 알림 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('SMS 메시지 내용을 여기에 입력하세요.'); }

유니코드 콘텐츠

한글처럼 유니코드 문자가 포함된 메시지를 전송할 때는 VonageMessage 인스턴스를 생성할 때 unicode 메서드를 함께 호출해야 합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * Vonage / SMS 알림 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('안녕하세요! 주문이 완료되었습니다.') ->unicode(); }

NOTE

한국어, 중국어, 일본어 등 유니코드 문자를 포함하는 메시지는 반드시 ->unicode()를 호출해야 정상적으로 전송됩니다.

발신 번호 변경

특정 알림에서 VONAGE_SMS_FROM에 설정된 기본 발신 번호 대신 다른 번호를 사용하고 싶다면, VonageMessage 인스턴스에서 from 메서드를 호출합니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * Vonage / SMS 알림 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('SMS 메시지 내용을 여기에 입력하세요.') ->from('15554443333'); }

클라이언트 참조 추가

사용자, 팀, 또는 고객별로 SMS 사용 비용을 추적하고 싶다면 알림에 "클라이언트 참조(client reference)"를 추가할 수 있습니다. Vonage는 이 참조값을 기준으로 리포트를 생성해 주므로, 특정 고객의 SMS 사용 현황을 쉽게 파악할 수 있습니다. 클라이언트 참조는 최대 40자까지 지정할 수 있습니다.

use Illuminate\Notifications\Messages\VonageMessage; /** * Vonage / SMS 알림 표현을 반환합니다. */ public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->clientReference((string) $notifiable->id) ->content('SMS 메시지 내용을 여기에 입력하세요.'); }

SMS 알림 라우팅

Vonage 알림을 올바른 전화번호로 전송하려면, 알림 대상 엔티티(예: User 모델)에 routeNotificationForVonage 메서드를 정의합니다.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; class User extends Authenticatable { use Notifiable; /** * Vonage 채널의 알림 라우팅 정보를 반환합니다. */ public function routeNotificationForVonage(Notification $notification): string { return $this->phone_number; } }

알림

Slack 알림

사전 준비

Slack 알림을 전송하려면 먼저 Composer로 Slack 알림 채널 패키지를 설치해야 합니다:

composer require laravel/slack-notification-channel

그리고 Slack 워크스페이스에서 사용할 Slack App을 생성해야 합니다.

앱을 생성한 워크스페이스 내에서만 알림을 전송하는 경우, App에 chat:write, chat:write.public, chat:write.customize 스코프가 부여되어 있어야 합니다. 이 스코프들은 Slack 앱 관리 화면의 "OAuth & Permissions" 탭에서 추가할 수 있습니다.

설정이 완료되면 "OAuth & Permissions" 탭에서 "Bot User OAuth Token"을 복사하여 애플리케이션의 services.php 설정 파일에 추가합니다:

'slack' => [ 'notifications' => [ 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), ], ],

App 배포 (외부 워크스페이스 지원)

애플리케이션 사용자가 소유한 외부 Slack 워크스페이스에도 알림을 전송해야 한다면, Slack의 App 배포(Distribution) 절차를 거쳐야 합니다. 앱 관리 화면의 "Manage Distribution" 탭에서 배포를 관리할 수 있습니다. 배포가 완료된 후에는 Socialite를 활용하여 사용자 대신 Slack Bot 토큰을 발급받을 수 있습니다.

Slack 알림 포맷 정의

알림 클래스가 Slack 메시지 전송을 지원하려면 toSlack 메서드를 정의해야 합니다. 이 메서드는 $notifiable 엔티티를 받아 Illuminate\Notifications\Slack\SlackMessage 인스턴스를 반환해야 합니다.

Slack의 Block Kit API를 활용하면 헤더, 섹션, 구분선 등 다양한 블록으로 구성된 풍부한 메시지를 만들 수 있습니다. 아래 예시는 Slack Block Kit Builder에서 직접 미리볼 수 있습니다:

use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject; use Illuminate\Notifications\Slack\SlackMessage; /** * 알림의 Slack 표현을 반환합니다. */ public function toSlack(object $notifiable): SlackMessage { return (new SlackMessage) ->text('청구서 결제가 완료되었습니다!') ->headerBlock('청구서 결제 완료') ->contextBlock(function (ContextBlock $block) { $block->text('고객 #1234'); }) ->sectionBlock(function (SectionBlock $block) { $block->text('청구서가 결제되었습니다.'); $block->field("*청구서 번호:*\n1000")->markdown(); $block->field("*수신자:*\ntaylor@laravel.com")->markdown(); }) ->dividerBlock() ->sectionBlock(function (SectionBlock $block) { $block->text('축하합니다!'); }); }

Slack 인터랙티비티

Slack Block Kit의 사용자 인터랙션 처리 기능을 활용하려면 Slack App에서 "Interactivity"를 활성화하고, 요청을 수신할 애플리케이션 URL을 "Request URL"로 등록해야 합니다. 이 설정은 Slack 앱 관리 화면의 "Interactivity & Shortcuts" 탭에서 변경할 수 있습니다.

아래 예시는 actionsBlock 메서드를 사용하는 예시입니다. 사용자가 버튼을 클릭하면 Slack이 등록된 "Request URL"로 POST 요청을 전송하며, 요청 페이로드에는 클릭한 사용자 정보, 버튼 ID 등이 포함됩니다. 애플리케이션은 이 페이로드를 기반으로 적절한 처리를 수행하면 됩니다. 보안을 위해 반드시 요청이 Slack에서 왔는지 검증해야 합니다:

use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock; use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; use Illuminate\Notifications\Slack\SlackMessage; /** * 알림의 Slack 표현을 반환합니다. */ public function toSlack(object $notifiable): SlackMessage { return (new SlackMessage) ->text('청구서 결제가 완료되었습니다!') ->headerBlock('청구서 결제 완료') ->contextBlock(function (ContextBlock $block) { $block->text('고객 #1234'); }) ->sectionBlock(function (SectionBlock $block) { $block->text('청구서가 결제되었습니다.'); }) ->actionsBlock(function (ActionsBlock $block) { // ID를 지정하지 않으면 "button_acknowledge_invoice"가 기본값으로 사용됩니다... $block->button('청구서 확인')->primary(); // ID를 직접 지정하는 경우... $block->button('거절')->danger()->id('deny_invoice'); }); }

확인 모달 (Confirmation Modals)

버튼 클릭 시 사용자에게 최종 확인을 요구하고 싶다면 버튼 정의 시 confirm 메서드를 사용하세요. confirm 메서드는 확인 메시지 문자열과 ConfirmObject 인스턴스를 받는 클로저를 인수로 받습니다:

use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock; use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject; use Illuminate\Notifications\Slack\SlackMessage; /** * 알림의 Slack 표현을 반환합니다. */ public function toSlack(object $notifiable): SlackMessage { return (new SlackMessage) ->text('청구서 결제가 완료되었습니다!') ->headerBlock('청구서 결제 완료') ->contextBlock(function (ContextBlock $block) { $block->text('고객 #1234'); }) ->sectionBlock(function (SectionBlock $block) { $block->text('청구서가 결제되었습니다.'); }) ->actionsBlock(function (ActionsBlock $block) { $block->button('청구서 확인') ->primary() ->confirm( '결제를 확인하고 감사 이메일을 발송할까요?', function (ConfirmObject $dialog) { $dialog->confirm('예'); $dialog->deny('아니오'); } ); }); }

Slack 블록 디버깅

구성 중인 블록을 빠르게 확인하려면 SlackMessage 인스턴스에서 dd 메서드를 호출하세요. dd 메서드는 현재 페이로드를 미리볼 수 있는 Slack Block Kit Builder URL을 생성하여 브라우저에 출력합니다. true를 인수로 전달하면 URL 대신 원시(raw) 페이로드를 덤프합니다:

return (new SlackMessage) ->text('청구서 결제가 완료되었습니다!') ->headerBlock('청구서 결제 완료') ->dd();

Slack 알림 라우팅

Slack 알림이 올바른 팀과 채널로 전달되도록 하려면, 알림 대상 모델에 routeNotificationForSlack 메서드를 정의합니다. 이 메서드는 다음 세 가지 중 하나를 반환할 수 있습니다:

  • null — 알림 클래스 내부에서 to 메서드로 지정한 채널로 전송됩니다.
  • 채널명 문자열 — 예: #support-channel처럼 채널명을 직접 지정합니다.
  • SlackRoute 인스턴스 — OAuth 토큰과 채널명을 함께 지정합니다. 외부 워크스페이스로 전송할 때 사용합니다. 예: SlackRoute::make($this->slack_channel, $this->slack_token)

예를 들어 #support-channel을 반환하면, services.php에 설정된 Bot User OAuth Token과 연결된 워크스페이스의 해당 채널로 알림이 전송됩니다:

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; class User extends Authenticatable { use Notifiable; /** * Slack 알림을 전송할 채널을 지정합니다. */ public function routeNotificationForSlack(Notification $notification): mixed { return '#support-channel'; } }

외부 Slack 워크스페이스로 알림 전송

NOTE

외부 Slack 워크스페이스로 알림을 전송하기 전에 Slack App이 배포되어 있어야 합니다.

사용자가 소유한 외부 Slack 워크스페이스로 알림을 전송하려면, 먼저 해당 사용자의 Slack OAuth 토큰을 발급받아야 합니다. Laravel Socialite의 Slack 드라이버를 사용하면 사용자 인증과 Bot 토큰 발급을 간편하게 처리할 수 있습니다.

Bot 토큰을 발급받아 데이터베이스에 저장한 후에는 SlackRoute::make 메서드로 해당 사용자의 워크스페이스로 알림을 라우팅할 수 있습니다. 일반적으로 사용자가 알림을 수신할 채널을 직접 지정할 수 있는 UI도 함께 제공하는 것이 좋습니다:

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notification; use Illuminate\Notifications\Slack\SlackRoute; class User extends Authenticatable { use Notifiable; /** * Slack 알림을 전송할 채널을 지정합니다. */ public function routeNotificationForSlack(Notification $notification): mixed { return SlackRoute::make($this->slack_channel, $this->slack_token); } }

알림 현지화

Laravel은 현재 HTTP 요청의 로케일과 다른 언어로 알림을 발송하는 기능을 제공합니다. 알림이 큐에 저장되는 경우에도 지정한 로케일이 유지됩니다.

이를 위해 Illuminate\Notifications\Notification 클래스의 locale 메서드로 원하는 언어를 설정할 수 있습니다. 알림이 처리되는 동안 애플리케이션은 지정한 로케일로 전환되며, 처리가 완료되면 원래 로케일로 돌아옵니다.

$user->notify((new InvoicePaid($invoice))->locale('ko'));

여러 수신자에게 동시에 발송할 때는 Notification 파사드를 통해 로케일을 지정할 수 있습니다.

Notification::locale('ko')->send( $users, new InvoicePaid($invoice) );

사용자 선호 로케일

애플리케이션에 따라 각 사용자의 선호 언어를 DB에 저장하는 경우가 있습니다. 이럴 때는 알림을 보낼 때마다 매번 locale을 지정하는 대신, Notifiable 모델에 HasLocalePreference 인터페이스를 구현하면 Laravel이 자동으로 저장된 로케일을 사용합니다.

use Illuminate\Contracts\Translation\HasLocalePreference; class User extends Model implements HasLocalePreference { /** * 사용자의 선호 로케일을 반환합니다. */ public function preferredLocale(): string { return $this->locale; } }

인터페이스를 구현하면 알림과 Mailable 발송 시 Laravel이 자동으로 선호 로케일을 적용합니다. 따라서 별도로 locale 메서드를 호출할 필요가 없습니다.

$user->notify(new InvoicePaid($invoice));

NOTE

HasLocalePreference를 구현하면 메일(Mailable) 발송 시에도 동일하게 적용됩니다. 알림과 메일 모두 한 곳에서 로케일 설정을 관리할 수 있어 편리합니다.

테스트

Notification 파사드의 fake 메서드를 사용하면 실제 알림이 전송되는 것을 막을 수 있습니다. 테스트에서는 알림을 실제로 발송하는 것보다, Laravel이 올바른 알림을 전송하도록 지시받았는지를 확인하는 것으로 충분한 경우가 대부분입니다.

fake를 호출한 후에는 특정 사용자에게 알림이 전송되도록 지시되었는지 검증하고, 알림에 전달된 데이터도 확인할 수 있습니다:

<?php namespace Tests\Feature; use App\Notifications\OrderShipped; use Illuminate\Support\Facades\Notification; use Tests\TestCase; class ExampleTest extends TestCase { public function test_orders_can_be_shipped(): void { Notification::fake(); // 주문 배송 처리 수행... // 아무 알림도 전송되지 않았는지 확인... Notification::assertNothingSent(); // 특정 사용자에게 알림이 전송되었는지 확인... Notification::assertSentTo( [$user], OrderShipped::class ); // 특정 알림이 전송되지 않았는지 확인... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // 전송된 알림의 총 개수 확인... Notification::assertCount(3); } }

assertSentTo 또는 assertNotSentTo 메서드에 클로저를 전달하면, 전송된 알림이 특정 조건을 만족하는지 세밀하게 검증할 수 있습니다. 조건을 만족하는 알림이 하나 이상 존재하면 검증은 통과됩니다:

Notification::assertSentTo( $user, function (OrderShipped $notification, array $channels) use ($order) { return $notification->order->id === $order->id; } );

온디맨드 알림 테스트

테스트 대상 코드가 온디맨드 알림을 전송하는 경우, assertSentOnDemand 메서드로 해당 알림이 전송되었는지 확인할 수 있습니다:

Notification::assertSentOnDemand(OrderShipped::class);

assertSentOnDemand의 두 번째 인자로 클로저를 전달하면, 온디맨드 알림이 올바른 라우트 주소로 전송되었는지도 검증할 수 있습니다:

Notification::assertSentOnDemand( OrderShipped::class, function (OrderShipped $notification, array $channels, object $notifiable) use ($user) { return $notifiable->routes['mail'] === $user->email; } );

알림 이벤트

NotificationSending 이벤트

알림이 전송되기 직전에 알림 시스템은 Illuminate\Notifications\Events\NotificationSending 이벤트를 디스패치합니다. 이 이벤트에는 알림 수신 대상(notifiable) 엔티티와 알림 인스턴스가 포함됩니다. EventServiceProvider에서 이 이벤트에 대한 리스너를 등록할 수 있습니다.

use App\Listeners\CheckNotificationStatus; use Illuminate\Notifications\Events\NotificationSending; /** * 애플리케이션의 이벤트 리스너 매핑 * * @var array */ protected $listen = [ NotificationSending::class => [ CheckNotificationStatus::class, ], ];

NotificationSending 이벤트의 리스너 handle 메서드에서 false를 반환하면 해당 알림은 실제로 전송되지 않습니다. 특정 조건에 따라 알림 발송을 차단해야 할 때 유용합니다.

use Illuminate\Notifications\Events\NotificationSending; /** * 이벤트 처리 */ public function handle(NotificationSending $event): bool { return false; }

이벤트 리스너 안에서는 이벤트 객체의 notifiable, notification, channel 프로퍼티를 통해 알림 수신자나 알림 자체에 대한 정보를 확인할 수 있습니다.

/** * 이벤트 처리 */ public function handle(NotificationSending $event): void { // $event->channel — 전송 채널 (예: "mail", "database") // $event->notifiable — 알림 수신 대상 모델 // $event->notification — 알림 인스턴스 }

NotificationSent 이벤트

알림이 전송된 직후에는 Illuminate\Notifications\Events\NotificationSent 이벤트가 디스패치됩니다. 마찬가지로 notifiable 엔티티와 알림 인스턴스를 포함하며, EventServiceProvider에서 리스너를 등록해 사용할 수 있습니다.

use App\Listeners\LogNotification; use Illuminate\Notifications\Events\NotificationSent; /** * 애플리케이션의 이벤트 리스너 매핑 * * @var array */ protected $listen = [ NotificationSent::class => [ LogNotification::class, ], ];

NOTE

EventServiceProvider에 리스너를 등록한 뒤 php artisan event:generate 명령을 실행하면 리스너 클래스 파일이 자동으로 생성됩니다.

이벤트 리스너 안에서는 notifiable, notification, channel 외에도 response 프로퍼티를 통해 채널이 반환한 응답 값을 확인할 수 있습니다. 예를 들어 메일 채널의 경우 외부 메일 서비스 API 응답이 담겨 있어 발송 성공 여부 로깅에 활용할 수 있습니다.

/** * 이벤트 처리 */ public function handle(NotificationSent $event): void { // $event->channel — 전송 채널 // $event->notifiable — 알림 수신 대상 모델 // $event->notification — 알림 인스턴스 // $event->response — 채널에서 반환한 응답 값 }

커스텀 채널

Laravel은 기본적으로 여러 알림 채널을 제공하지만, 때로는 직접 드라이버를 작성해 원하는 방식으로 알림을 전송해야 할 수 있습니다. Laravel은 이를 간단하게 구현할 수 있도록 지원합니다.

채널 클래스 정의

커스텀 채널을 만들려면 send 메서드를 포함한 클래스를 정의합니다. 이 메서드는 $notifiable(알림 수신 대상)과 $notification(알림 인스턴스) 두 인수를 받습니다.

send 메서드 내부에서는 알림 객체의 메서드를 호출해 메시지 객체를 가져온 뒤, $notifiable 인스턴스에게 원하는 방식으로 알림을 전송하면 됩니다.

<?php namespace App\Notifications; use Illuminate\Notifications\Notification; class VoiceChannel { /** * 알림을 전송합니다. */ public function send(object $notifiable, Notification $notification): void { $message = $notification->toVoice($notifiable); // $notifiable 인스턴스에게 알림 전송... } }

커스텀 채널 사용

채널 클래스를 정의했다면, 알림의 via 메서드에서 해당 클래스명을 반환하면 됩니다. 아래 예시에서 toVoice 메서드는 음성 메시지를 표현하는 객체를 반환합니다. 예를 들어, 음성 메시지를 표현할 전용 VoiceMessage 클래스를 별도로 정의할 수 있습니다.

<?php namespace App\Notifications; use App\Notifications\Messages\VoiceMessage; use App\Notifications\VoiceChannel; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; class InvoicePaid extends Notification { use Queueable; /** * 알림 채널을 반환합니다. */ public function via(object $notifiable): string { return VoiceChannel::class; } /** * 알림의 음성 표현을 반환합니다. */ public function toVoice(object $notifiable): VoiceMessage { // ... } }

NOTE

커스텀 채널 클래스는 Laravel의 서비스 컨테이너를 통해 자동으로 의존성이 주입됩니다. 따라서 VoiceChannel의 생성자에서 필요한 서비스를 타입힌트로 선언하면 별도 설정 없이 바인딩된 인스턴스를 주입받을 수 있습니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 7월 2일