title: Symfony notifier attach custom metadata to envelope
body: <p>I'm using the Symfony notifier and messenger components to asynchronously send SMS messages (and in the future push and email notifications).</p>
  <p>Everything works just fine, however once a message is sent, I'd like to log information about it.</p>
  <p>I can catch a successful message by subscribing to <code>WorkerMessageHandledEvent</code> which provides me the <code>Message</code> object, along with the containing <code>Envelope</code> and all its <code>Stamp</code> objects inside. From all the available information, I'll be logging this in my database using an entity named <code>MessageLog</code>.</p>
  <pre class="lang-php prettyprint-override"><code>class MessengerSubscriber implements EventSubscriberInterface {
  
      public static function getSubscribedEvents() {
          return [
              WorkerMessageHandledEvent::class =&gt; ['onHandled']
          ];
      }
  
      public function onHandled(WorkerMessageHandledEvent $event) {
          $log = new MessageLog();
          $log-&gt;setSentAt(new DateTime());
  
          if($event-&gt;getEnvelope()-&gt;getMessage() instanceof SmsMessage) {
              $log-&gt;setSubject($event-&gt;getEnvelope()-&gt;getMessage()-&gt;getSubject());
              $log-&gt;setRecipient($event-&gt;getEnvelope()-&gt;getMessage()-&gt;getPhone());
          }
  
          // Do more tracking
      }
  
  }
  </code></pre>
  <p>What I'd like to do, is track the object that &quot;invoked&quot; the message. For example, if I have a news feed, and posting a post sends out a notification, I'd like to attribute each logged message to that post (to display audience reach/delivery stats per post - and from an admin POV auditing and reporting).</p>
  <p>I've tried to go about adding a <code>Stamp</code>, or other means of trying to attach custom metadata to the message, but it seems to be abstracted when using the <code>symfony/notifier</code> bundle.</p>
  <p>The below is what I'm using to send notifications (more or less WIP):</p>
  <pre class="lang-php prettyprint-override"><code>class PostService {
  
      protected NotifierInterface $notifier;
  
      public function ___construct(NotifierInterface $notifier) {
          $this-&gt;notifier = $notifier;
      }
  
      public function sendNotifications(Post $post) {
          $notification = new PostNotification($post);
          
          $recipients = [];
          foreach($post-&gt;getNewsFeed()-&gt;getSubscribers() as $user) {
              $recipients[] = new Recipient($user-&gt;getEmail(), $user-&gt;getMobilePhone());
          }
  
          $this-&gt;notifier-&gt;send($notification, ...$recipients);
      }
  
  }
  </code></pre>
  <pre class="lang-php prettyprint-override"><code>class PostNotification extends Notification implements SmsNotificationInterface {
  
      protected Post $post;
  
      public function __construct(Post $post) {
          parent::__construct();
          $this-&gt;post = $post;
      }
  
      public function getChannels(RecipientInterface $recipient): array {
          return ['sms'];
      }
  
      public function asSmsMessage(SmsRecipientInterface $recipient, string $transport = null): ?SmsMessage {
          if($transport === 'sms') {
              return new SmsMessage($recipient-&gt;getPhone(), $this-&gt;getPostContentAsSms());
          }
  
          return null;
      }
  
      private function getPostContentAsSms() {
          return $post-&gt;getTitle().&quot;\n\n&quot;.$post-&gt;getContent();
      }
  
  }
  </code></pre>
  <p>By the time this is all done, this is all I have in the <code>WorkerMessageHandledEvent</code></p>
  <pre><code>^ Symfony\Component\Messenger\Event\WorkerMessageHandledEvent^ {#5590
    -envelope: Symfony\Component\Messenger\Envelope^ {#8022
      -stamps: array:7 [
        &quot;Symfony\Component\Messenger\Stamp\BusNameStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\BusNameStamp^ {#10417
            -busName: &quot;messenger.bus.default&quot;
          }
        ]
        &quot;Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp^ {#10419
            -id: &quot;2031&quot;
          }
        ]
        &quot;Symfony\Component\Messenger\Stamp\TransportMessageIdStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\TransportMessageIdStamp^ {#10339
            -id: &quot;2031&quot;
          }
        ]
        &quot;Symfony\Component\Messenger\Stamp\ReceivedStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\ReceivedStamp^ {#5628
            -transportName: &quot;async&quot;
          }
        ]
        &quot;Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp^ {#7306}
        ]
        &quot;Symfony\Component\Messenger\Stamp\AckStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\AckStamp^ {#7159
            -ack: Closure(Envelope $envelope, Throwable $e = null)^ {#6205
              class: &quot;Symfony\Component\Messenger\Worker&quot;
              this: Symfony\Component\Messenger\Worker {#5108 …}
              use: {
                $transportName: &quot;async&quot;
                $acked: &amp; false
              }
            }
          }
        ]
        &quot;Symfony\Component\Messenger\Stamp\HandledStamp&quot; =&gt; array:1 [
          0 =&gt; Symfony\Component\Messenger\Stamp\HandledStamp^ {#11445
            -result: Symfony\Component\Notifier\Message\SentMessage^ {#2288
              -original: Symfony\Component\Notifier\Message\NullMessage^ {#6625
                -decoratedMessage: Symfony\Component\Notifier\Message\SmsMessage^ {#10348
                  -transport: null
                  -subject: &quot;..................................................&quot;
                  -phone: &quot;0412345678&quot;
                }
              }
              -transport: &quot;null&quot;
              -messageId: null
            }
            -handlerName: &quot;Symfony\Component\Notifier\Messenger\MessageHandler::__invoke&quot;
          }
        ]
      ]
      -message: Symfony\Component\Notifier\Message\SmsMessage^ {#10348}
    }
    -receiverName: &quot;async&quot;
  }
  </code></pre>
  <p>The doco shows me ways to add my own stamps to the envelope, which I'm guessing I can use to attach metadata such as my <code>Post</code> object, but this means I need to use the <code>MessageBusInterface</code> to send notifications. I don't want to do because I would like to route messages through the <code>NotifierInterface</code> to gain all the benefits of channel policies, texter transports, etc.</p>
  <hr />
  <p>tl;dr: how do I get some metadata through to a <code>WorkerMessageHandledEvent</code> if I send a message using the <code>NotifierInterface</code></p>