알림
번역일: 2026년 6월 21일
알림
소개
Laravel은 이메일 발송 외에도 이메일, SMS(Vonage 통해, 구 Nexmo), 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 인스턴스를 받아, 해당 대상에 맞는 채널 목록을 반환합니다. 예를 들어 사용자가 SMS를 선호하는지 여부에 따라 채널을 다르게 지정할 수 있습니다.
/**
* 알림 전송 채널을 반환합니다.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
}알림 큐 처리
WARNING
알림을 큐에 넣기 전에 큐를 설정하고 큐 워커를 실행해야 합니다.
외부 API 호출이 필요한 채널의 경우 알림 전송에 시간이 걸릴 수 있습니다. 응답 속도를 높이기 위해 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;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
/**
* 최대 재시도 횟수
*
* @var int
*/
public $tries = 5;
/**
* 타임아웃(초)
*
* @var int
*/
public $timeout = 120;
/**
* 실패 전 허용할 최대 예외 횟수
*
* @var int
*/
public $maxExceptions = 3;
// ...
}큐 알림 데이터를 암호화하여 보호하고 싶다면 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;
// ...
}재시도 대기 시간이나 재시도 만료 시점을 세밀하게 제어하려면 backoff, retryUntil 메서드를 정의할 수 있습니다.
use DateTime;
/**
* 재시도 전 대기 시간(초)을 반환합니다.
*/
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());생성자에서 호출하는 방법도 있습니다.
<?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
{
// ...
}즉석 알림(On-Demand)
애플리케이션의 사용자 테이블에 저장되지 않은 임시 대상에게 알림을 전송할 때는 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)을 조합해 메시지를 만들 수 있습니다.
/**
* 알림의 메일 표현을 반환합니다.
*/
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 처럼 알림 생성자에서 주입한 데이터를 자유롭게 사용할 수 있습니다.
위 예시처럼 인사말, 본문, 버튼, 마무리 문장을 조합하면 mail 채널이 이를 아름다운 반응형 HTML 이메일로 렌더링하며, 일반 텍스트 버전도 자동으로 생성합니다.
NOTE
메일 알림을 전송할 때 config/app.php의 name 설정값이 이메일 헤더와 푸터에 사용됩니다. 반드시 올바르게 설정되어 있는지 확인하세요.
오류 메시지
결제 실패처럼 오류 상황을 알리는 이메일에는 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]
);
}HTML 뷰와 텍스트 뷰를 모두 지정하려면 배열로 전달합니다.
/**
* 알림의 메일 표현을 반환합니다.
*/
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]
);
}발신자 커스터마이징
기본 발신 주소는 config/mail.php에 설정되어 있습니다. 특정 알림에서만 다른 발신 주소를 사용하려면 from 메서드를 사용합니다.
/**
* 알림의 메일 표현을 반환합니다.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('barrett@example.com', 'Barrett Blair')
->line('...');
}수신자 커스터마이징
mail 채널을 사용할 때 알림 시스템은 자동으로 notifiable 모델의 email 속성을 수신 주소로 사용합니다. 다른 이메일 주소를 사용하려면 모델에 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;
/**
* mail 채널의 수신 주소를 반환합니다.
*
* @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('...');
}