diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js
--- a/lib/handlers/db-ops-handler.react.js
+++ b/lib/handlers/db-ops-handler.react.js
@@ -31,7 +31,7 @@
     }
     prevQueueFront.current = queueFront;
 
-    const { ops, dispatchMetadata } = queueFront;
+    const { ops, dispatchMetadata, notificationsCreationData } = queueFront;
     void (async () => {
       if (ops) {
         await processDBStoreOperations(ops);
@@ -39,7 +39,11 @@
           const messageIDs = ops.outboundP2PMessages.map(
             message => message.messageID,
           );
-          processOutboundMessages(messageIDs, dispatchMetadata?.dmOpID);
+          processOutboundMessages(
+            messageIDs,
+            dispatchMetadata?.dmOpID,
+            notificationsCreationData,
+          );
         }
       }
       dispatch({
diff --git a/lib/push/send-hooks.react.js b/lib/push/send-hooks.react.js
--- a/lib/push/send-hooks.react.js
+++ b/lib/push/send-hooks.react.js
@@ -96,7 +96,7 @@
 }
 
 function useSendPushNotifs(): (
-  notifCreationData: NotificationsCreationData,
+  notifCreationData: ?NotificationsCreationData,
 ) => Promise<?PerUserTargetedNotifications> {
   const rawMessageInfos = useSelector(state => state.messageStore.messages);
   const thickRawThreadInfos = useSelector(thickRawThreadInfosSelector);
@@ -110,7 +110,10 @@
   const { encryptedNotifUtilsAPI } = getConfig();
 
   return React.useCallback(
-    async (notifCreationData: NotificationsCreationData) => {
+    async (notifCreationData: ?NotificationsCreationData) => {
+      if (!notifCreationData) {
+        return;
+      }
       const deviceID = await getContentSigningKey();
       const senderDeviceDescriptor = { senderDeviceID: deviceID };
       const { messageDatas } = notifCreationData;
diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js
--- a/lib/shared/dm-ops/process-dm-ops.js
+++ b/lib/shared/dm-ops/process-dm-ops.js
@@ -116,9 +116,17 @@
         }
         return;
       }
-      const { rawMessageInfos, updateInfos } = await dmOpSpecs[
-        dmOp.type
-      ].processDMOperation(dmOp, viewerID, utilities);
+
+      const dmOpSpec = dmOpSpecs[dmOp.type];
+      const notificationsCreationDataPromise = (async () => {
+        return await dmOpSpec.notificationsCreationData?.(dmOp, utilities);
+      })();
+
+      const [{ rawMessageInfos, updateInfos }, notificationsCreationData] =
+        await Promise.all([
+          dmOpSpec.processDMOperation(dmOp, viewerID, utilities),
+          notificationsCreationDataPromise,
+        ]);
 
       const { rawMessageInfos: allNewMessageInfos } =
         mergeUpdatesWithMessageInfos(rawMessageInfos, updateInfos);
@@ -203,6 +211,7 @@
             updateInfos,
             outboundP2PMessages,
             messageIDWithoutAutoRetry,
+            notificationsCreationData,
           },
         },
         dispatchMetadata,
diff --git a/lib/tunnelbroker/peer-to-peer-context.js b/lib/tunnelbroker/peer-to-peer-context.js
--- a/lib/tunnelbroker/peer-to-peer-context.js
+++ b/lib/tunnelbroker/peer-to-peer-context.js
@@ -9,11 +9,13 @@
   useTunnelbroker,
 } from './tunnelbroker-context.js';
 import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
+import { useSendPushNotifs } from '../push/send-hooks.react.js';
 import {
   type AuthMetadata,
   IdentityClientContext,
   type IdentityClientContextType,
 } from '../shared/identity-client-context.js';
+import type { NotificationsCreationData } from '../types/notif-types.js';
 import {
   type OutboundP2PMessage,
   outboundP2PMessageStatuses,
@@ -30,6 +32,7 @@
   +processOutboundMessages: (
     outboundMessageIDs: ?$ReadOnlyArray<string>,
     dmOpID: ?string,
+    notificationsCreationData: ?NotificationsCreationData,
   ) => void,
   +getDMOpsSendingPromise: () => {
     +promise: Promise<$ReadOnlyArray<string>>,
@@ -210,28 +213,41 @@
     Array<{
       +outboundMessageIDs: ?$ReadOnlyArray<string>,
       +dmOpID: ?string,
+      +notificationsCreationData: ?NotificationsCreationData,
     }>,
   >([]);
   const promiseRunning = React.useRef<boolean>(false);
 
   const { createOlmSessionsWithPeer: peerOlmSessionsCreator } =
     usePeerOlmSessionsCreatorContext();
+  const sendPushNotifs = useSendPushNotifs();
 
   const processOutboundMessages = React.useCallback(
-    (outboundMessageIDs: ?$ReadOnlyArray<string>, dmOpID: ?string) => {
-      processingQueue.current.push({ outboundMessageIDs, dmOpID });
+    (
+      outboundMessageIDs: ?$ReadOnlyArray<string>,
+      dmOpID: ?string,
+      notificationsCreationData: ?NotificationsCreationData,
+    ) => {
+      processingQueue.current.push({
+        outboundMessageIDs,
+        dmOpID,
+        notificationsCreationData,
+      });
       if (!promiseRunning.current) {
         promiseRunning.current = true;
         void (async () => {
           do {
             const queueFront = processingQueue.current.shift();
             try {
-              const sentMessagesIDs = await processOutboundP2PMessages(
-                sendMessageToDevice,
-                identityContext,
-                peerOlmSessionsCreator,
-                queueFront?.outboundMessageIDs,
-              );
+              const [sentMessagesIDs] = await Promise.all([
+                processOutboundP2PMessages(
+                  sendMessageToDevice,
+                  identityContext,
+                  peerOlmSessionsCreator,
+                  queueFront?.outboundMessageIDs,
+                ),
+                sendPushNotifs(notificationsCreationData),
+              ]);
               if (queueFront.dmOpID) {
                 dmOpsSendingPromiseResolvers.current
                   .get(queueFront.dmOpID)
@@ -258,7 +274,12 @@
         })();
       }
     },
-    [peerOlmSessionsCreator, identityContext, sendMessageToDevice],
+    [
+      sendPushNotifs,
+      peerOlmSessionsCreator,
+      identityContext,
+      sendMessageToDevice,
+    ],
   );
 
   const broadcastEphemeralMessage = React.useCallback(