Laravel中的Notifications系统如何发送邮件和短信? (多渠道通知)

8次阅读

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

Laravel中的Notifications系统如何发送邮件和短信? (多渠道通知)

Laravel 的 Notifications 系统本身不直接发送邮件或短信,它只负责「分发通知」;真正发邮件靠 MailChannel,发短信得自己配第三方服务(比如 Twilio、阿里云短信),并实现对应的 Channel

如何让 Notification 同时走邮件和短信?

关键在通知类的 via() 方法返回多个渠道,且每个渠道对应的方法(如 tomail()toTwilio())都存在:

  • via() 必须返回包含 'mail' 和自定义短信渠道名(如 'twilio')的数组
  • 必须定义 toMail($notifiable),返回 Mailable 对象
  • 必须定义 toTwilio($notifiable)(或其他渠道名),返回包含 tofrombody 的数组
  • 短信渠道需注册到 config/services.php 并在 appProvidersAppServiceProvider 中用 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 官方只内置了 MailChannelDatabaseChannelBroadcastChannel 等几种通用渠道,短信涉及大量第三方 API 差异(认证方式、参数名、签名规则、模板审核),没法统一抽象。所以:

  • 没有 toSms() 这种全局方法 —— 你得按所用服务商命名,比如 toTwilio()toAliyunSms()
  • 每种短信服务都要单独封装一个 Channel 类,并在 via() 中显式引用
  • 错误处理必须自己加:比如 try/catch 捕获 http 异常,避免一条短信失败导致整个通知中断

发邮件失败会影响短信发送吗?

不会,但默认是同步执行的 —— 如果你没配置队列,MailChannelTwilioChannel 会按 via() 数组顺序依次调用,其中一个抛异常(比如邮件 SMTP 连接超时),后续渠道就不会执行。

  • 加队列是最稳妥的做法:php artisan queue:work + 在通知类中实现 ShouldQueue 接口
  • 各渠道执行彼此隔离:邮件失败不会阻止短信发出,反之亦然
  • 队列任务失败后可重试,但要注意短信重复发送问题(比如支付成功通知被重发两次)

容易忽略的兼容性细节

多渠道通知里最常踩的坑不在逻辑,而在数据结构和生命周期:

  • $notifiable 必须实现 routeNotificationForTwilio() 方法(或同名渠道方法),否则 toTwilio() 拿不到手机号
  • 邮件模板里的 {{ $notifiable->name }} 和短信里的 $notifiable->phone 来源不同,别假设字段名一致
  • 数据库通知表 notificationsdata 字段是 jsON,但短信渠道通常不存这里 —— 它是纯传输层,不落库
  • 测试时别只 mock 邮件:用 Notification::fake() 只拦截通知分发,不模拟实际发送,短信仍可能真发出去

text=ZqhQzanResources