Creating and Sending Notifications

Creating and Sending Notifications

New in version 5.0: The Notifier component was introduced in Symfony 5.0.

Installation

Current web applications use many different channels to send messages to the users (e.g. SMS, Slack messages, emails, push notifications, etc.). The Notifier component in Symfony is an abstraction on top of all these channels. It provides a dynamic way to manage how the messages are sent. Get the Notifier installed using:

  1. $ composer require symfony/notifier

Channels: Chatters, Texters, Email and Browser

The notifier component can send notifications to different channels. Each channel can integrate with different providers (e.g. Slack or Twilio SMS) by using transports.

The notifier component supports the following channels:

Tip

Use secrets to securily store your API’s tokens.

SMS Channel

The SMS channel uses Symfony\Component\Notifier\Texter classes to send SMS messages to mobile phones. This feature requires subscribing to a third-party service that sends SMS messages. Symfony provides integration with a couple popular SMS services:

ServicePackageDSN
AllMySmssymfony/allmysms-notifierallmysms://LOGIN:APIKEY@default?from=FROM
Clickatellsymfony/clickatell-notifierclickatell://ACCESS_TOKEN@default?from=FROM
Esendexsymfony/esendex-notifieresendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM
FakeSmssymfony/fake-sms-notifierfakesms+email://MAILER_SERVICE_ID?to=TO&from=FROM
FreeMobilesymfony/free-mobile-notifierfreemobile://LOGIN:PASSWORD@default?phone=PHONE
GatewayApisymfony/gatewayapi-notifiergatewayapi://TOKEN@default?from=FROM
Infobipsymfony/infobip-notifierinfobip://AUTH_TOKEN@HOST?from=FROM
Iqsmssymfony/iqsms-notifieriqsms://LOGIN:PASSWORD@default?from=FROM
LightSmssymfony/light-sms-notifierlightsms://LOGIN:TOKEN@default?from=PHONE
MessageBirdsymfony/message-bird-notifiermessagebird://TOKEN@default?from=FROM
Mobytsymfony/mobyt-notifiermobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM
Nexmosymfony/nexmo-notifiernexmo://KEY:SECRET@default?from=FROM
Octopushsymfony/octopush-notifieroctopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE
OvhCloudsymfony/ovh-cloud-notifierovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME
Sendinbluesymfony/sendinblue-notifiersendinblue://API_KEY@default?sender=PHONE
Sinchsymfony/sinch-notifiersinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM
Smsapisymfony/smsapi-notifiersmsapi://TOKEN@default?from=FROM
SmsBiurassymfony/sms-biuras-notifiersmsbiuras://UID:API_KEY@default?from=FROM&test_mode=0
SpotHitsymfony/spothit-notifierspothit://TOKEN@default?from=FROM
Twiliosymfony/twilio-notifiertwilio://SID:TOKEN@default?from=FROM

New in version 5.1: The OvhCloud, Sinch and FreeMobile integrations were introduced in Symfony 5.1.

New in version 5.2: The Smsapi, Infobip, Mobyt, Esendex and Sendinblue integrations were introduced in Symfony 5.2.

New in version 5.3: The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, SmsBiuras and MessageBird integrations were introduced in Symfony 5.3.

To enable a texter, add the correct DSN in your .env file and configure the texter_transports:

  1. # .env
  2. TWILIO_DSN=twilio://SID:[email protected]?from=FROM
  • YAML

    1. # config/packages/notifier.yaml
    2. framework:
    3. notifier:
    4. texter_transports:
    5. twilio: '%env(TWILIO_DSN)%'
  • XML

    1. <!-- config/packages/notifier.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <container xmlns="http://symfony.com/schema/dic/services"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:framework="http://symfony.com/schema/dic/symfony"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd
    8. http://symfony.com/schema/dic/symfony
    9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    10. <framework:config>
    11. <framework:notifier>
    12. <framework:texter-transport name="twilio">
    13. %env(TWILIO_DSN)%
    14. </framework:texter-transport>
    15. </framework:notifier>
    16. </framework:config>
    17. </container>
  • PHP

    1. // config/packages/notifier.php
    2. use Symfony\Config\FrameworkConfig;
    3. return static function (FrameworkConfig $framework) {
    4. $framework->notifier()
    5. ->texterTransport('twilio', '%env(TWILIO_DSN)%')
    6. ;
    7. };

Chat Channel

The chat channel is used to send chat messages to users by using Symfony\Component\Notifier\Chatter classes. Symfony provides integration with these chat services:

ServicePackageDSN
Discordsymfony/discord-notifierdiscord://TOKEN@default?webhook_id=ID
FakeChatsymfony/fake-chat-notifierfakechat+email://default?to=TO&from=FROM
Firebasesymfony/firebase-notifierfirebase://USERNAME:PASSWORD@default
Gittersymfony/gitter-notifiergitter://TOKEN@default?room_id=ROOM_ID
GoogleChatsymfony/google-chat-notifiergooglechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY
LinkedInsymfony/linked-in-notifierlinkedin://TOKEN:USER_ID@default
Mattermostsymfony/mattermost-notifiermattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL
Mercuresymfony/mercure-notifiermercure://HUB_ID?topic=TOPIC
MicrosoftTeamssymfony/microsoft-teams-notifiermicrosoftteams://default/PATH
RocketChatsymfony/rocket-chat-notifierrocketchat://TOKEN@ENDPOINT?channel=CHANNEL
Slacksymfony/slack-notifierslack://TOKEN@default?channel=CHANNEL
Telegramsymfony/telegram-notifiertelegram://TOKEN@default?channel=CHAT_ID
Zulipsymfony/zulip-notifierzulip://EMAIL:TOKEN@HOST?channel=CHANNEL

New in version 5.1: The Firebase, Mattermost and RocketChat integrations were introduced in Symfony 5.1. The Slack DSN changed in Symfony 5.1 to use Slack Incoming Webhooks instead of legacy tokens.

New in version 5.2: The GoogleChat, LinkedIn, Zulip and Discord integrations were introduced in Symfony 5.2. The Slack DSN changed in Symfony 5.2 to use Slack Web API again same as in 5.0.

New in version 5.3: The Gitter, Mercure, FakeChat and Microsoft Teams integrations were introduced in Symfony 5.3.

Chatters are configured using the chatter_transports setting:

  1. # .env
  2. SLACK_DSN=slack://[email protected]?channel=CHANNEL
  • YAML

    1. # config/packages/notifier.yaml
    2. framework:
    3. notifier:
    4. chatter_transports:
    5. slack: '%env(SLACK_DSN)%'
  • XML

    1. <!-- config/packages/notifier.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <container xmlns="http://symfony.com/schema/dic/services"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:framework="http://symfony.com/schema/dic/symfony"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd
    8. http://symfony.com/schema/dic/symfony
    9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    10. <framework:config>
    11. <framework:notifier>
    12. <framework:chatter-transport name="slack">
    13. %env(SLACK_DSN)%
    14. </framework:chatter-transport>
    15. </framework:notifier>
    16. </framework:config>
    17. </container>
  • PHP

    1. // config/packages/notifier.php
    2. use Symfony\Config\FrameworkConfig;
    3. return static function (FrameworkConfig $framework) {
    4. $framework->notifier()
    5. ->chatterTransport('slack', '%env(SLACK_DSN)%')
    6. ;
    7. };

Email Channel

The email channel uses the Symfony Mailer to send notifications using the special Symfony\Bridge\Twig\Mime\NotificationEmail. It is required to install the Twig bridge along with the Inky and CSS Inliner Twig extensions:

  1. $ composer require symfony/twig-pack twig/cssinliner-extra twig/inky-extra

After this, configure the mailer. You can also set the default “from” email address that should be used to send the notification emails:

  • YAML

    1. # config/packages/mailer.yaml
    2. framework:
    3. mailer:
    4. dsn: '%env(MAILER_DSN)%'
    5. envelope:
    6. sender: '[email protected]'
  • XML

    1. <!-- config/packages/mailer.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <container xmlns="http://symfony.com/schema/dic/services"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:framework="http://symfony.com/schema/dic/symfony"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd
    8. http://symfony.com/schema/dic/symfony
    9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    10. <framework:config>
    11. <framework:mailer
    12. dsn="%env(MAILER_DSN)%"
    13. >
    14. <framework:envelope
    15. sender="[email protected]"
    16. />
    17. </framework:mailer>
    18. </framework:config>
    19. </container>
  • PHP

    1. // config/packages/mailer.php
    2. use Symfony\Config\FrameworkConfig;
    3. return static function (FrameworkConfig $framework) {
    4. $framework->mailer()
    5. ->dsn('%env(MAILER_DSN)%')
    6. ->envelope()
    7. ->sender('[email protected]')
    8. ;
    9. };

Configure to use Failover or Round-Robin Transports

Besides configuring one or more separate transports, you can also use the special || and && characters to implement a failover or round-robin transport:

  • YAML

    1. # config/packages/notifier.yaml
    2. framework:
    3. notifier:
    4. chatter_transports:
    5. # Send notifications to Slack and use Telegram if
    6. # Slack errored
    7. main: '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%'
    8. # Send notifications to the next scheduled transport calculated by round robin
    9. roundrobin: '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%'
  • XML

    1. <!-- config/packages/notifier.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <container xmlns="http://symfony.com/schema/dic/services"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:framework="http://symfony.com/schema/dic/symfony"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd
    8. http://symfony.com/schema/dic/symfony
    9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    10. <framework:config>
    11. <framework:notifier>
    12. <!-- Send notifications to Slack and use Telegram if
    13. Slack errored -->
    14. <framework:chatter-transport name="slack">
    15. %env(SLACK_DSN)% || %env(TELEGRAM_DSN)%
    16. </framework:chatter-transport>
    17. <!-- Send notifications to the next scheduled transport
    18. calculated by round robin -->
    19. <framework:chatter-transport name="slack"><![CDATA[
    20. %env(SLACK_DSN)% && %env(TELEGRAM_DSN)%
    21. ]]></framework:chatter-transport>
    22. </framework:notifier>
    23. </framework:config>
    24. </container>
  • PHP

    1. // config/packages/notifier.php
    2. use Symfony\Config\FrameworkConfig;
    3. return static function (FrameworkConfig $framework) {
    4. $framework->notifier()
    5. // Send notifications to Slack and use Telegram if
    6. // Slack errored
    7. ->chatterTransport('main', '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%')
    8. // Send notifications to the next scheduled transport calculated by round robin
    9. ->chatterTransport('roundrobin', '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%')
    10. ;
    11. };

Creating & Sending Notifications

To send a notification, autowire the Symfony\Component\Notifier\NotifierInterface (service ID notifier). This class has a send() method that allows you to send aSymfony\Component\Notifier\Notification\Notificationto aSymfony\Component\Notifier\Recipient\Recipient`:

  1. // src/Controller/InvoiceController.php
  2. namespace App\Controller;
  3. use Symfony\Component\Notifier\Notification\Notification;
  4. use Symfony\Component\Notifier\NotifierInterface;
  5. use Symfony\Component\Notifier\Recipient\Recipient;
  6. class InvoiceController extends AbstractController
  7. {
  8. /**
  9. * @Route("/invoice/create")
  10. */
  11. public function create(NotifierInterface $notifier)
  12. {
  13. // ...
  14. // Create a Notification that has to be sent
  15. // using the "email" channel
  16. $notification = (new Notification('New Invoice', ['email']))
  17. ->content('You got a new invoice for 15 EUR.');
  18. // The receiver of the Notification
  19. $recipient = new Recipient(
  20. $user->getEmail(),
  21. $user->getPhonenumber()
  22. );
  23. // Send the notification to the recipient
  24. $notifier->send($notification, $recipient);
  25. // ...
  26. }
  27. }

The Notification is created by using two arguments: the subject and channels. The channels specify which channel (or transport) should be used to send the notification. For instance, [‘email’, ‘sms’]` will send both an email and sms notification to the user.

The default notification also has a content() andemoji() method to set the notification content and icon.

Symfony provides the following recipients:

Symfony\Component\Notifier\Recipient\NoRecipient

This is the default and is useful when there is no need to have information about the receiver. For example, the browser channel uses the current requests’s session flashbag;

Symfony\Component\Notifier\Recipient\Recipient

This can contain both email address and phonenumber of the user. This recipient can be used for all channels (depending on whether they are actually set).

New in version 5.2: The AdminRecipient class was removed in Symfony 5.2, you should use Recipient instead.

Configuring Channel Policies

Instead of specifying the target channels on creation, Symfony also allows you to use notification importance levels. Update the configuration to specify what channels should be used for specific levels (using channel_policy):

  • YAML

    1. # config/packages/notifier.yaml
    2. framework:
    3. notifier:
    4. # ...
    5. channel_policy:
    6. # Use SMS, Slack and email for urgent notifications
    7. urgent: ['sms', 'chat/slack', 'email']
    8. # Use Slack for highly important notifications
    9. high: ['chat/slack']
    10. # Use browser for medium and low notifications
    11. medium: ['browser']
    12. low: ['browser']
  • XML

    1. <!-- config/packages/notifier.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <container xmlns="http://symfony.com/schema/dic/services"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:framework="http://symfony.com/schema/dic/symfony"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd
    8. http://symfony.com/schema/dic/symfony
    9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    10. <framework:config>
    11. <framework:notifier>
    12. <!-- ... -->
    13. <framework:channel-policy>
    14. <!-- Use SMS, Slack and Email for urgent notifications -->
    15. <framework:urgent>sms</framework:urgent>
    16. <framework:urgent>chat/slack</framework:urgent>
    17. <framework:urgent>email</framework:urgent>
    18. <!-- Use Slack for highly important notifications -->
    19. <framework:high>chat/slack</framework:high>
    20. <!-- Use browser for medium and low notifications -->
    21. <framework:medium>browser</framework:medium>
    22. <framework:low>browser</framework:low>
    23. </framework:channel-policy>
    24. </framework:notifier>
    25. </framework:config>
    26. </container>
  • PHP

    1. // config/packages/notifier.php
    2. use Symfony\Config\FrameworkConfig;
    3. return static function (FrameworkConfig $framework) {
    4. // ...
    5. $framework->notifier()
    6. // Use SMS, Slack and email for urgent notifications
    7. ->channelPolicy('urgent', ['sms', 'chat/slack', 'email'])
    8. // Use Slack for highly important notifications
    9. ->channelPolicy('high', ['chat/slack'])
    10. // Use browser for medium and low notifications
    11. ->channelPolicy('medium', ['browser'])
    12. ->channelPolicy('medium', ['browser'])
    13. ;
    14. };

Now, whenever the notification’s importance is set to “high”, it will be sent using the Slack transport:

  1. // ...
  2. class InvoiceController extends AbstractController
  3. {
  4. /**
  5. * @Route("/invoice/create")
  6. */
  7. public function invoice(NotifierInterface $notifier)
  8. {
  9. // ...
  10. $notification = (new Notification('New Invoice'))
  11. ->content('You got a new invoice for 15 EUR.')
  12. ->importance(Notification::IMPORTANCE_HIGH);
  13. $notifier->send($notification, new Recipient('[email protected]'));
  14. // ...
  15. }
  16. }

Customize Notifications

You can extend the Notification or Recipient base classes to customize their behavior. For instance, you can overwrite the getChannels() method to only returnsms` if the invoice price is very high and the recipient has a phone number:

  1. namespace App\Notifier;
  2. use Symfony\Component\Notifier\Notification\Notification;
  3. use Symfony\Component\Notifier\Recipient\RecipientInterface;
  4. use Symfony\Component\Notifier\Recipient\SmsRecipientInterface;
  5. class InvoiceNotification extends Notification
  6. {
  7. private $price;
  8. public function __construct(int $price)
  9. {
  10. $this->price = $price;
  11. }
  12. public function getChannels(RecipientInterface $recipient)
  13. {
  14. if (
  15. $this->price > 10000
  16. && $recipient instanceof SmsRecipientInterface
  17. ) {
  18. return ['sms'];
  19. }
  20. return ['email'];
  21. }
  22. }

Customize Notification Messages

Each channel has its own notification interface that you can implement to customize the notification message. For instance, if you want to modify the message based on the chat service, implement Symfony\Component\Notifier\Notification\ChatNotificationInterface and its `asChatMessage() method:

  1. // src/Notifier/InvoiceNotification.php
  2. namespace App\Notifier;
  3. use Symfony\Component\Notifier\Message\ChatMessage;
  4. use Symfony\Component\Notifier\Notification\ChatNotificationInterface;
  5. use Symfony\Component\Notifier\Notification\Notification;
  6. use Symfony\Component\Notifier\Recipient\SmsRecipientInterface;
  7. class InvoiceNotification extends Notification implements ChatNotificationInterface
  8. {
  9. private $price;
  10. public function __construct(int $price)
  11. {
  12. $this->price = $price;
  13. }
  14. public function asChatMessage(RecipientInterface $recipient, string $transport = null): ?ChatMessage
  15. {
  16. // Add a custom emoji if the message is sent to Slack
  17. if ('slack' === $transport) {
  18. return (new ChatMessage('You\'re invoiced '.$this->price.' EUR.'))
  19. ->emoji('money');
  20. }
  21. // If you return null, the Notifier will create the ChatMessage
  22. // based on this notification as it would without this method.
  23. return null;
  24. }
  25. }

The Symfony\Component\Notifier\Notification\SmsNotificationInterface and Symfony\Component\Notifier\Notification\EmailNotificationInterface also exists to modify messages send to those channels.

Disabling Delivery

While developing (or testing), you may want to disable delivery of notifications entirely. You can do this by forcing Notifier to use the NullTransport for all configured texter and chatter transports only in the dev (and/or test) environment:

  1. # config/packages/dev/notifier.yaml
  2. framework:
  3. notifier:
  4. texter_transports:
  5. twilio: 'null://null'
  6. chatter_transports:
  7. slack: 'null://null'

Learn more

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.