알림

업데이트됨

번역일: 2026년 7월 15일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 7월 15일
번역 갱신
2026년 7월 15일

알림

소개

이메일 발송 지원 외에도, Laravel은 이메일, SMS(Vonage, 이전 명칭 Nexmo 경유), Slack 등 다양한 전달 채널을 통한 알림 발송을 지원합니다. 또한 수십 가지 채널을 통해 알림을 발송할 수 있도록 커뮤니티에서 제작한 알림 채널도 다양하게 만들어져 있습니다! 알림은 데이터베이스에 저장하여 웹 인터페이스에 표시할 수도 있습니다.

일반적으로 알림은 애플리케이션에서 발생한 일을 사용자에게 알리는 짧은 정보성 메시지여야 합니다. 예를 들어, 청구 애플리케이션을 개발하고 있다면 이메일 및 SMS 채널을 통해 사용자에게 "Invoice Paid" 알림을 발송할 수 있습니다.

알림

알림 생성하기

Laravel에서 각 알림은 하나의 클래스로 표현되며, 보통 app/Notifications 디렉토리에 저장됩니다. 처음에는 이 디렉토리가 없어도 괜찮습니다. 아래 Artisan 명령어를 실행하면 자동으로 생성됩니다.

php artisan make:notification InvoicePaid

이 명령어를 실행하면 app/Notifications 디렉토리에 새 알림 클래스가 생성됩니다. 각 알림 클래스에는 via 메서드와 채널별 메시지를 구성하는 메서드(예: toMail, toDatabase)가 포함되어 있습니다. via 메서드는 알림을 어떤 채널로 전송할지 결정하고, 각 채널 메서드는 해당 채널에 맞는 메시지 형태로 변환하는 역할을 합니다.

알림

알림 전송

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

ShouldQueue 인터페이스가 구현되어 있더라도 즉시 알림을 발송하고 싶다면 sendNow 메서드를 사용하세요.

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()->plus(minutes: 10); $user->notify((new InvoicePaid($invoice))->delay($delay));

채널별로 다른 지연 시간을 지정할 수도 있습니다.

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

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

/** * 알림 지연 발송 시간을 반환합니다. * * @return array<string, \Illuminate\Support\Carbon> */ public function withDelay(object $notifiable): array { return [ 'mail' => now()->plus(minutes: 5), 'sms' => now()->plus(minutes: 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', ]; }

큐 Job 속성 커스터마이징

알림 클래스에 큐 관련 속성(어트리뷰트)을 정의하면 내부적으로 생성되는 큐 Job의 동작을 제어할 수 있습니다.

<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; use Illuminate\Queue\Attributes\MaxExceptions; use Illuminate\Queue\Attributes\Timeout; use Illuminate\Queue\Attributes\Tries; #[Tries(5)] #[Timeout(120)] #[MaxExceptions(3)] class InvoicePaid extends Notification implements ShouldQueue { use Queueable; // ... }

큐에 저장되는 알림 데이터를 암호화하여 보안을 강화하고 싶다면 ShouldBeEncrypted 인터페이스를 추가하세요.

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

어트리뷰트 외에도 backoffretryUntil 메서드로 재시도 대기 시간과 타임아웃을 지정할 수 있습니다.

use DateTime; /** * 재시도 전 대기할 초(seconds)를 반환합니다. */ public function backoff(): int { return 3; } /** * 알림 Job이 타임아웃될 시각을 반환합니다. */ public function retryUntil(): DateTime { return now()->plus(minutes: 5); }

NOTE

이 속성과 메서드에 대한 자세한 내용은 큐 Job 문서를 참고하세요.

큐 알림 미들웨어

큐에 등록된 알림에도 큐 Job과 동일하게 미들웨어를 적용할 수 있습니다. 알림 클래스에 middleware 메서드를 정의하면 되며, $notifiable$channel 변수를 활용해 채널에 따라 다른 미들웨어를 반환할 수 있습니다.

use Illuminate\Queue\Middleware\RateLimited; /** * 알림 Job에 적용할 미들웨어를 반환합니다. * * @return array<int, object> */ public function middleware(object $notifiable, string $channel) { return match ($channel) { 'mail' => [new RateLimited('postmark')], 'slack' => [new RateLimited('slack')], default => [], }; }

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

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

큐 커넥션의 after_commit 옵션이 false로 설정된 경우에도, 알림 전송 시 afterCommit 메서드를 체이닝하면 모든 트랜잭션이 커밋된 후에 알림이 디스패치됩니다.

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

또는 생성자에서 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(); }

알림 발송 후 처리

알림이 발송된 후 추가 작업을 실행하려면 알림 클래스에 afterSending 메서드를 정의하세요. 이 메서드는 알림 대상, 채널 이름, 채널 응답값을 인수로 받습니다.

/** * 알림 발송 후 실행할 작업을 처리합니다. */ public function afterSending(object $notifiable, string $channel, mixed $response): void { // ... }

온디맨드 알림

애플리케이션에 등록된 사용자가 아닌 외부 수신자에게 알림을 보내야 할 때는 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));

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

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

위 예시에서 $this->invoice->id를 사용하고 있습니다. 알림 메시지 생성에 필요한 데이터는 알림 클래스의 생성자를 통해 주입하면 됩니다.

이 예시에서는 인사말, 텍스트, 행동 유도 버튼, 마지막 텍스트 순서로 메시지를 구성했습니다. MailMessage가 제공하는 메서드들을 활용하면 짧은 트랜잭션 이메일을 빠르게 작성할 수 있습니다. 메일 채널은 이 구성 요소들을 반응형 HTML 이메일 템플릿과 플레인 텍스트 버전으로 자동 변환합니다. 아래는 실제로 생성되는 이메일 예시입니다.

NOTE

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

오류 메시지

결제 실패 등 오류 상황을 사용자에게 알릴 때는 메시지를 작성할 때 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('support@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 메서드를 사용하세요. attach 메서드의 첫 번째 인수로 파일의 절대 경로를 전달합니다.

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

NOTE

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

파일 첨부 시 표시 이름이나 MIME 타입을 지정하려면 attach 메서드의 두 번째 인수로 배열을 전달하세요.

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

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

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

특정 파일 시스템 디스크에 저장된 파일을 첨부하려면 attachFromStorageDisk 메서드를 사용하세요. 디스크 이름과 해당 디스크 내 파일 경로를 인수로 전달합니다.

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

원시 데이터 첨부

attachData 메서드를 사용하면 원시 바이트 문자열을 첨부 파일로 추가할 수 있습니다. attachData 메서드 호출 시 첨부 파일에 지정할 파일명을 함께 전달해야 합니다.

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

태그 및 메타데이터 추가

Mailgun, Postmark 등 일부 서드파티 이메일 서비스는 메시지에 "태그"와 "메타데이터"를 추가하는 기능을 제공합니다. 이를 활용하면 애플리케이션에서 발송한 이메일을 그룹화하거나 추적할 수 있습니다. tag 메서드와 metadata 메서드를 사용하여 태그와 메타데이터를 추가할 수 있습니다.

/** * 알림의 메일 표현을 반환합니다. */ 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과 즉시 알림(On-Demand Notifications)

즉시 알림(on-demand notification)을 발송하는 경우, 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를 직접 반환하면 브라우저에서 미리볼 수 있습니다.

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 이메일로 변환해 주며, 동시에 일반 텍스트(plain-text) 버전도 자동 생성됩니다.

알림 생성하기

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

NOTE

Markdown 이메일을 작성할 때 불필요한 들여쓰기를 사용하지 마세요. Markdown 표준에 따라 들여쓰기된 내용은 코드 블록으로 렌더링됩니다.

버튼 컴포넌트

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

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

패널 컴포넌트

패널 컴포넌트는 지정한 텍스트 블록을 나머지 알림 내용과 약간 다른 배경색의 박스 안에 렌더링합니다. 특정 내용을 강조하여 독자의 시선을 끌고 싶을 때 유용합니다:

<x-mail::panel> 이 부분은 패널 안에 표시됩니다. </x-mail::panel>

테이블 컴포넌트

테이블 컴포넌트는 Markdown 표를 HTML 테이블로 변환해 렌더링합니다. Markdown 표 문법을 그대로 작성하면 되며, 표준 Markdown 표 정렬 문법(:)을 사용한 열 정렬도 지원합니다:

<x-mail::table> | 항목 | 수량 | 금액 | | ------------- | :-----------: | ------------: | | 상품 A | 1 |10,000 | | 상품 B | 2 |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 파일을 추가하면 됩니다. 파일을 저장한 후 mail 설정 파일의 theme 옵션 값을 새 테마의 파일명(확장자 제외)으로 변경하세요.

특정 알림에만 다른 테마를 적용하려면, 알림 메일 메시지를 구성할 때 theme 메서드를 호출합니다. theme 메서드에 사용할 테마 이름을 문자열로 전달하세요:

/** * 알림의 메일 표현을 반환합니다. */ 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, ]; }

알림이 데이터베이스에 저장될 때, type 컬럼에는 기본적으로 알림 클래스의 전체 클래스명이 저장되고 read_at 컬럼은 null로 설정됩니다. 이 동작을 커스터마이징하려면 알림 클래스에 databaseTypeinitialDatabaseReadAtValue 메서드를 정의하면 됩니다.

use Illuminate\Support\Carbon; /** * 알림의 데이터베이스 타입을 반환합니다. */ public function databaseType(object $notifiable): string { return 'invoice-paid'; } /** * "read_at" 컬럼의 초기값을 반환합니다. */ public function initialDatabaseReadAtValue(): ?Carbon { return null; }

`toDatabase` vs. `toArray`

toArray 메서드는 broadcast 채널에서도 사용됩니다. JavaScript 프론트엔드로 브로드캐스트할 데이터를 결정할 때 동일한 메서드가 호출되기 때문입니다. database 채널과 broadcast 채널에서 서로 다른 배열 구조를 사용하고 싶다면, toArray 대신 toDatabase 메서드를 별도로 정의하세요.

알림 조회

알림이 데이터베이스에 저장되면, 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 관계를 사용하세요. 마찬가지로 최신 순으로 정렬됩니다.

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

읽은 알림만 가져오려면 readNotifications 관계를 사용하세요.

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

NOTE

JavaScript 클라이언트에서 알림을 조회하려면, 현재 사용자와 같은 notifiable 엔티티의 알림을 반환하는 알림 컨트롤러를 애플리케이션에 정의한 뒤, 해당 컨트롤러 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 필드가 자동으로 포함됩니다. 이 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); });

React, Vue, Svelte에서 사용하기

Laravel Echo는 React, Vue, Svelte용 훅(hook)을 제공하여 알림 수신을 더욱 간편하게 처리할 수 있습니다. useEchoNotification 훅을 호출하면 알림을 수신할 수 있으며, 컴포넌트가 언마운트될 때 자동으로 채널 구독도 해제됩니다.

React

import { useEchoNotification } from "@laravel/echo-react"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, );

Vue

<script setup lang="ts"> import { useEchoNotification } from "@laravel/echo-vue"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, ); </script>

Svelte

<script> import { useEchoNotification } from "@laravel/echo-svelte"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, ); </script>

기본적으로 이 훅은 모든 종류의 알림을 수신합니다. 특정 알림 타입만 수신하고 싶다면, useEchoNotification의 세 번째 인자로 타입 문자열 또는 배열을 전달하세요.

React

import { useEchoNotification } from "@laravel/echo-react"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, 'App.Notifications.InvoicePaid', );

Vue

<script setup lang="ts"> import { useEchoNotification } from "@laravel/echo-vue"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, 'App.Notifications.InvoicePaid', ); </script>

Svelte

<script> import { useEchoNotification } from "@laravel/echo-svelte"; useEchoNotification( `App.Models.User.${userId}`, (notification) => { console.log(notification.type); }, 'App.Notifications.InvoicePaid', ); </script>

TypeScript를 사용하는 경우, 알림 페이로드의 타입을 제네릭으로 지정하면 타입 안전성과 편집기 자동완성 기능을 활용할 수 있습니다.

type InvoicePaidNotification = { invoice_id: number; created_at: string; }; useEchoNotification<InvoicePaidNotification>( `App.Models.User.${userId}`, (notification) => { console.log(notification.invoice_id); console.log(notification.created_at); console.log(notification.type); }, 'App.Notifications.InvoicePaid', );

알림 채널 커스터마이징

브로드캐스트 알림이 전송될 채널을 직접 지정하고 싶다면, 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; } }

SMS 알림

사전 준비

Laravel의 SMS 알림은 Vonage(구 Nexmo)를 통해 발송됩니다. 시작하기 전에 아래 패키지를 설치하세요:

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

패키지 자체에 설정 파일이 포함되어 있지만, 별도로 퍼블리시하지 않아도 됩니다. 대신 .env 파일에 Vonage 공개 키와 시크릿 키를 환경 변수로 지정하면 됩니다:

VONAGE_KEY=your-vonage-key VONAGE_SECRET=your-vonage-secret

키를 설정했다면, SMS를 발송할 기본 발신 번호도 지정해야 합니다. 발신 번호는 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 메서드를 호출해야 합니다. 이 설정을 빠뜨리면 한글 등 비ASCII 문자가 제대로 전송되지 않을 수 있습니다:

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

발신 번호 커스터마이징

특정 알림을 기본 발신 번호(VONAGE_SMS_FROM)가 아닌 다른 번호로 발송하고 싶다면, from 메서드를 사용하세요:

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

클라이언트 참조 추가

사용자, 팀, 또는 고객별로 SMS 사용 비용을 추적하고 싶다면 클라이언트 참조 값을 설정할 수 있습니다. Vonage는 이 값을 기준으로 리포트를 생성해 주며, 최대 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의 App 관리 탭 중 "OAuth & Permissions"에서 추가할 수 있습니다.

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

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

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

애플리케이션의 사용자가 소유한 외부 Slack 워크스페이스에 알림을 전송해야 하는 경우, Slack의 "Manage Distribution" 탭에서 App을 배포(distribute)해야 합니다. App이 배포된 이후에는 Laravel 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\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("*수신자:*\nuser@example.com")->markdown(); }) ->dividerBlock() ->sectionBlock(function (SectionBlock $block) { $block->text('감사합니다!'); }); }

Block Kit Builder 템플릿 직접 사용

메서드 체이닝으로 메시지를 구성하는 대신, Slack의 Block Kit Builder에서 생성한 JSON 페이로드를 usingBlockKitTemplate 메서드에 직접 전달할 수도 있습니다:

use Illuminate\Notifications\Slack\SlackMessage; use Illuminate\Support\Str; /** * 알림의 Slack 표현을 반환합니다. */ public function toSlack(object $notifiable): SlackMessage { $template = <<<JSON { "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": "팀 공지사항" } }, { "type": "section", "text": { "type": "plain_text", "text": "현재 채용 중입니다!" } } ] } JSON; return (new SlackMessage) ->usingBlockKitTemplate($template); }

Slack 인터랙티비티

Slack Block Kit은 사용자가 메시지 내 버튼 등의 요소와 직접 상호작용할 수 있는 강력한 기능을 제공합니다. 이 기능을 사용하려면 Slack App의 "Interactivity & Shortcuts" 탭에서 "Interactivity"를 활성화하고, 애플리케이션에서 처리할 "Request URL"을 등록해야 합니다.

아래 예시에서 actionsBlock 메서드를 사용하면, 사용자가 버튼을 클릭했을 때 Slack이 등록된 "Request URL"로 POST 요청을 전송합니다. 요청 페이로드에는 버튼을 클릭한 Slack 사용자 정보, 클릭된 버튼의 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'); }); }

확인 모달

버튼을 클릭하기 전에 사용자에게 최종 확인을 요구하고 싶다면, 버튼 정의 시 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 메서드는 Block Kit Builder URL을 생성하여 브라우저에서 바로 미리 볼 수 있도록 덤프합니다. true를 인수로 전달하면 원시 JSON 페이로드를 덤프합니다:

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이 연결된 워크스페이스의 #support-channel 채널로 알림이 전송됩니다:

<?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이 배포(distribute)되어 있어야 합니다.

사용자가 소유한 외부 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); } }

알림 다국어(Localization) 처리

Laravel은 현재 HTTP 요청의 로케일과 다른 언어로 알림을 전송할 수 있습니다. 알림이 큐에 추가된 경우에도 지정한 로케일이 유지됩니다.

이를 위해 Illuminate\Notifications\Notification 클래스의 locale 메서드로 원하는 언어를 지정합니다. 알림이 처리되는 동안에는 지정한 로케일로 전환되고, 처리가 완료되면 이전 로케일로 자동 복원됩니다.

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

여러 수신자에게 보낼 때는 Notification 파사드를 사용해 로케일을 지정할 수도 있습니다.

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

사용자별 선호 로케일

애플리케이션에서 사용자마다 선호 언어를 저장하는 경우, 알림을 보낼 때마다 매번 locale을 지정하는 것은 번거롭습니다. Notifiable 모델에 HasLocalePreference 인터페이스를 구현하면, Laravel이 알림 전송 시 저장된 로케일을 자동으로 사용합니다.

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

인터페이스를 구현하면, 알림과 Mailable을 전송할 때 Laravel이 자동으로 preferredLocale()의 반환값을 사용합니다. 따라서 별도로 locale 메서드를 호출할 필요가 없습니다.

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

NOTE

한국어 서비스라면 locale 컬럼에 'ko'를 저장해 두고, 글로벌 서비스라면 'en', 'ja' 등을 함께 관리하는 방식으로 활용할 수 있습니다.

테스트

Notification 파사드의 fake 메서드를 사용하면 실제로 알림이 전송되지 않도록 막을 수 있습니다. 일반적으로 알림 전송 자체는 테스트하려는 비즈니스 로직과 직접적인 관련이 없습니다. 대부분의 경우, Laravel이 특정 알림을 전송하도록 지시받았는지 여부만 확인하는 것으로 충분합니다.

Notification::fake()를 호출한 뒤, 특정 사용자에게 알림이 전송되었는지 검증하거나 알림 객체가 받은 데이터를 검사할 수 있습니다.

Pest

<?php use App\Notifications\OrderShipped; use Illuminate\Support\Facades\Notification; test('주문을 배송 처리할 수 있다', function () { Notification::fake(); // 주문 배송 처리 수행... // 아무 알림도 전송되지 않았는지 확인... Notification::assertNothingSent(); // 지정한 사용자에게 알림이 전송되었는지 확인... Notification::assertSentTo( [$user], OrderShipped::class ); // 특정 알림이 전송되지 않았는지 확인... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // 특정 알림이 두 번 전송되었는지 확인... Notification::assertSentTimes(WeeklyReminder::class, 2); // 전송된 알림의 총 개수 확인... Notification::assertCount(3); });

PHPUnit

<?php namespace Tests\Feature; use App\Notifications\OrderShipped; use Illuminate\Support\Facades\Notification; use Tests\TestCase; class ExampleTest extends TestCase { public function test_주문을_배송_처리할__있다(): void { Notification::fake(); // 주문 배송 처리 수행... // 아무 알림도 전송되지 않았는지 확인... Notification::assertNothingSent(); // 지정한 사용자에게 알림이 전송되었는지 확인... Notification::assertSentTo( [$user], OrderShipped::class ); // 특정 알림이 전송되지 않았는지 확인... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // 특정 알림이 두 번 전송되었는지 확인... Notification::assertSentTimes(WeeklyReminder::class, 2); // 전송된 알림의 총 개수 확인... 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") 엔티티와 알림 인스턴스가 포함됩니다. 애플리케이션에서 이 이벤트에 대한 이벤트 리스너를 등록해 활용할 수 있습니다.

use Illuminate\Notifications\Events\NotificationSending; class CheckNotificationStatus { /** * 이벤트를 처리합니다. */ public function handle(NotificationSending $event): void { // ... } }

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

/** * 이벤트를 처리합니다. */ public function handle(NotificationSending $event): bool { return false; }

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

/** * 이벤트를 처리합니다. */ public function handle(NotificationSending $event): void { // $event->channel — 발송 채널 (예: 'mail', 'slack' 등) // $event->notifiable — 알림 수신 대상 엔티티 // $event->notification — 알림 인스턴스 }

NotificationSent 이벤트

알림이 성공적으로 발송된 후에는 Illuminate\Notifications\Events\NotificationSent 이벤트가 디스패치됩니다. 이 이벤트 역시 알림 대상 엔티티와 알림 인스턴스를 포함합니다. 발송 완료 후 로깅이나 후처리가 필요할 때 이 이벤트를 활용하세요.

use Illuminate\Notifications\Events\NotificationSent; class LogNotification { /** * 이벤트를 처리합니다. */ public function handle(NotificationSent $event): void { // ... } }

이벤트 리스너 안에서는 notifiable, notification, channel, response 프로퍼티에 접근할 수 있습니다. response 프로퍼티를 통해 채널 드라이버가 반환한 발송 결과를 확인할 수 있습니다.

/** * 이벤트를 처리합니다. */ public function handle(NotificationSent $event): void { // $event->channel — 발송 채널 (예: 'mail', 'slack' 등) // $event->notifiable — 알림 수신 대상 엔티티 // $event->notification — 알림 인스턴스 // $event->response — 채널 드라이버의 발송 응답 결과 }

커스텀 채널

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 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 7월 15일