Cuando quieras añadir nuevas formas de entregar notificaciones desde un paquete, diseña por separado la selección del canal y la determinación del destinatario. En esta página se usa como ejemplo un pequeño canal que registra eventos operativos en el log para explicar cómo se resuelven las clases que ofrece el paquete y qué verificaciones necesitas al actualizarlo. Si lo sustituyes por un envío a un servicio externo, el reparto de responsabilidades entre el canal y la notificación es el mismo.
Esta página se basa en la implementación de Laravel Framework v13.38.0. Para las operaciones básicas con notificaciones, consulta Notificaciones; para el entorno de pruebas de paquetes, consulta Pruebas de paquetes.
El nombre de la clase de canal que devuelves en via() indica sobre qué objeto se llama a send(). En cambio, el valor que se obtiene de routeNotificationFor() es el destino que usa ese canal. No es necesario que ambos tengan el mismo nombre.
NotificationSender pasa el nombre de canal elegido por via() a ChannelManager::driver(). Si ChannelManager no lo encuentra entre los nombres integrados ni entre los registrados, y el nombre corresponde a una clase existente, resuelve esa clase con el contenedor. Si solo lo usas por nombre de clase, no necesitas Notification::extend() ni un service provider en el paquete. Basta con que el autoload de Composer encuentre la clase y que el contenedor pueda resolver las dependencias del constructor.
Ofrecer el canal desde el paquete
El paquete de ejemplo Acme\OperationsLog registra un nombre de evento sin información sensible junto con el nombre del equipo de operaciones destinatario. En una aplicación Laravel, Psr\Log\LoggerInterface está vinculado al servicio de log, así que puedes recibirlo en el constructor.
El objeto recibido puede ser un modelo que use el trait Notifiable o un destinatario bajo demanda creado con Notification::route(). En el primer caso se devuelve el valor de routeNotificationForOperationsLog(); en el segundo, el valor registrado con route('operationsLog', ...). Para no tratar como entregada una notificación sin destino, este ejemplo lanza una excepción. Si lo sustituyes por una entrega externa real, comprueba también el destino y el resultado del envío, y no ocultes los fallos como si fueran éxitos.
No incluyas tokens de acceso ni datos personales en los nombres de evento ni en los destinos que registras en el log. Este ejemplo es un envío al log para ilustrar la resolución de canales y las pruebas; no es una implementación de entrega a un servicio externo.
Definir la notificación y el destino en la aplicación
La notificación de la aplicación devuelve la clase del canal y solo define el mensaje que se pasa al canal. Si usas ShouldQueue y Queueable, las llamadas normales a notify() pasan por la cola.
Si indicas el destino en el momento, la clave de Notification::route() no es el nombre de la clase del canal, sino la clave que el canal usa al llamar a routeNotificationFor('operationsLog', ...).
Si envías desde un modelo de la aplicación, añade el siguiente método al modelo que usa Notifiable.
Con $user->notify(new HealthCheckPassed()) sobre este modelo también se elige el mismo canal. Configura la conexión de cola e inicia un worker que procese la cola operations-log.
El propio OperationsLogChannel queda retenido en el Manager por cada canal, así que no guardes el destinatario ni el contenido de la notificación en propiedades del canal: obtenlos en cada llamada a partir de los argumentos de send(). Así evitas que un worker de cola de larga duración arrastre información de la notificación anterior.
Cuando necesitas un alias corto
Usa Notification::extend() en un service provider normal del paquete solo si quieres que los usuarios indiquen en via() un nombre corto en lugar del nombre de clase.
Haz que el provider se cargue antes de que empiece la entrega, por ejemplo mediante el descubrimiento automático de paquetes. En las notificaciones que elijan el alias, cambia via() a ['acme-operations-log'] y usa el mismo nombre como clave en viaQueues(). operationsLog, que sirve para obtener el destino, es una clave distinta, así que no hace falta cambiarla. Usa un nombre que no colisione con los canales integrados.
El Manager retiene los canales resueltos por nombre. Aunque vuelvas a registrar la lógica de creación del alias en el mismo proceso, la instancia ya creada no se reemplaza. Verifica los cambios en la forma de registro también en aplicaciones y workers recién iniciados.
Probar la entrega por separado de fake
Notification::fake() sirve para verificar la intención de enviar una notificación. No confirma que funcionen el send() del canal ni la obtención de la ruta. En las pruebas de entrega, usa el Manager de notificaciones real y sustituye LoggerInterface por uno de prueba.
El siguiente ejemplo se ejecuta desde el TestCase de Testbench. Con notifyNow() puedes ejecutar el procesamiento del canal sin iniciar un worker, incluso en notificaciones ShouldQueue.
Además, comprueba que se lanza una excepción cuando no hay destino y, si ofreces un alias, que se resuelve desde un arranque nuevo. Si lo usas a través de colas, prueba también, en una aplicación de verificación con un worker de cola en ejecución, que los jobs llegan a la cola operations-log y se procesan.
NotificationSender divide las notificaciones ShouldQueue en un job por canal y elige la cola según la clave de viaQueues(). Si el send() del canal lanza una excepción, dispara NotificationFailed y vuelve a lanzar la excepción; si termina con normalidad, dispara NotificationSent. La configuración de reintentos de la cola sigue la configuración de la aplicación. Ten en cuenta que, si ocultas la excepción dentro del canal, la entrega se tratará como exitosa aunque haya fallado.
Fuentes primarias consultadas
Última modificación el 22 de octubre de 2026