Laravel通知系统通过via()返回多渠道并实现对应toXxx()方法实现邮件与短信同时发送;需自定义短信Channel因官方未内置统一抽象,且各服务商API差异大;启用队列可避免单渠道失败阻断其他渠道。

Laravel 的 Notifications 系统本身不直接发送邮件或短信,它只负责「分发通知」;真正发邮件靠 MailChannel,发短信得自己配第三方服务(比如 Twilio、阿里云短信),并实现对应的 Channel。
如何让 Notification 同时走邮件和短信?
关键在通知类的 via() 方法返回多个渠道,且每个渠道对应的方法(如 toMail()、toTwilio())都存在:
-
via()必须返回包含'mail'和自定义短信渠道名(如'twilio')的数组 - 必须定义
toMail($notifiable),返回Mailable对象 - 必须定义
toTwilio($notifiable)(或其他渠道名),返回包含to、from、body的数组 - 短信渠道需注册到
config/services.php并在App\Providers\AppServiceProvider中用Notification::extend()绑定
public function via($notifiable)
{
return ['mail', 'twilio'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('您的订单已确认。')
->action('查看订单', url('/orders/'.$this->order->id));
}
public function toTwilio($notifiable)
{
return [
'to' => $notifiable->phone,
'from' => config('services.twilio.from'),
'body' => '【MyApp】您的订单已确认:'.$this->order->id,
];
}
为什么发短信要自己写 Channel 而不是开箱即用?
Laravel 官方只内置了 MailChannel、DatabaseChannel、BroadcastChannel 等几种通用渠道,短信涉及大量第三方 API 差异(认证方式、参数名、签名规则、模板审核),没法统一抽象。所以:
- 没有
toSms()这种全局方法 —— 你得按所用服务商命名,比如toTwilio()或toAliyunSms() - 每种短信服务都要单独封装一个
Channel类,并在via()中显式引用 - 错误处理必须自己加:比如
try/catch捕获 HTTP 异常,避免一条短信失败导致整个通知中断
发邮件失败会影响短信发送吗?
不会,但默认是同步执行的 —— 如果你没配置队列,MailChannel 和 TwilioChannel 会按 via() 数组顺序依次调用,其中一个抛异常(比如邮件 SMTP 连接超时),后续渠道就不会执行。
- 加队列是最稳妥的做法:
php artisan queue:work+ 在通知类中实现ShouldQueue接口 - 各渠道执行彼此隔离:邮件失败不会阻止短信发出,反之亦然
- 队列任务失败后可重试,但要注意短信重复发送问题(比如支付成功通知被重发两次)
容易忽略的兼容性细节
多渠道通知里最常踩的坑不在逻辑,而在数据结构和生命周期:
-
$notifiable必须实现routeNotificationForTwilio()方法(或同名渠道方法),否则toTwilio()拿不到手机号 - 邮件模板里的
{{ $notifiable->name }}和短信里的$notifiable->phone来源不同,别假设字段名一致 - 数据库通知表
notifications的data字段是 JSON,但短信渠道通常不存这里 —— 它是纯传输层,不落库 - 测试时别只 mock 邮件:用
Notification::fake()只拦截通知分发,不模拟实际发送,短信仍可能真发出去










