diff --git a/lib/hooks/ops-hooks.js b/lib/hooks/ops-hooks.js
--- a/lib/hooks/ops-hooks.js
+++ b/lib/hooks/ops-hooks.js
@@ -8,12 +8,17 @@
 
 function useDispatchWithMessageSource(): (
   action: SuperAction,
-  messageSourceMetadata: MessageSourceMetadata,
+  messageSourceMetadata: ?MessageSourceMetadata,
 ) => mixed {
   const dispatch = useDispatch();
   return React.useCallback(
-    (action: SuperAction, messageSourceMetadata: MessageSourceMetadata) =>
-      dispatch({ ...action, messageSourceMetadata }),
+    (action: SuperAction, messageSourceMetadata: ?MessageSourceMetadata) => {
+      if (messageSourceMetadata) {
+        dispatch({ ...action, messageSourceMetadata });
+      } else {
+        dispatch(action);
+      }
+    },
     [dispatch],
   );
 }
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
@@ -5,14 +5,19 @@
 import { dmOpSpecs } from './dm-op-specs.js';
 import { useLoggedInUserInfo } from '../../hooks/account-hooks.js';
 import { useGetLatestMessageEdit } from '../../hooks/latest-message-edit.js';
+import { useDispatchWithMessageSource } from '../../hooks/ops-hooks.js';
+import type { MessageSourceMetadata } from '../../types/db-ops-types.js';
 import {
   type DMOperation,
   processDMOpsActionType,
   queueDMOpsActionType,
 } from '../../types/dm-ops.js';
-import { useDispatch, useSelector } from '../../utils/redux-utils.js';
+import { useSelector } from '../../utils/redux-utils.js';
 
-function useProcessDMOperation(): (dmOp: DMOperation) => Promise<void> {
+function useProcessDMOperation(): (
+  dmOp: DMOperation,
+  metadata: ?MessageSourceMetadata,
+) => Promise<void> {
   const fetchMessage = useGetLatestMessageEdit();
   const threadInfos = useSelector(state => state.threadStore.threadInfos);
 
@@ -24,11 +29,11 @@
     [fetchMessage, threadInfos],
   );
 
-  const dispatch = useDispatch();
+  const dispatchWithMessageSource = useDispatchWithMessageSource();
   const loggedInUserInfo = useLoggedInUserInfo();
   const viewerID = loggedInUserInfo?.id;
   return React.useCallback(
-    async (dmOp: DMOperation) => {
+    async (dmOp: DMOperation, metadata: ?MessageSourceMetadata) => {
       if (!viewerID) {
         console.log('ignored DMOperation because logged out');
         return;
@@ -40,29 +45,34 @@
       );
       if (!processingCheckResult.isProcessingPossible) {
         if (processingCheckResult.reason.type === 'missing_thread') {
-          dispatch({
+          const action = {
             type: queueDMOpsActionType,
             payload: {
               operation: dmOp,
               threadID: processingCheckResult.reason.threadID,
               timestamp: Date.now(),
             },
-          });
+          };
+
+          dispatchWithMessageSource(action, metadata);
         }
         return;
       }
       const { rawMessageInfos, updateInfos } = await dmOpSpecs[
         dmOp.type
       ].processDMOperation(dmOp, viewerID, utilities);
-      dispatch({
+
+      const action = {
         type: processDMOpsActionType,
         payload: {
           rawMessageInfos,
           updateInfos,
         },
-      });
+      };
+
+      dispatchWithMessageSource(action, metadata);
     },
-    [dispatch, viewerID, utilities],
+    [viewerID, utilities, dispatchWithMessageSource],
   );
 }
 
diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js
--- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js
+++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js
@@ -70,7 +70,11 @@
   const processDMOperation = useProcessDMOperation();
 
   return React.useCallback(
-    async (decryptedMessageContent: string, senderInfo: SenderInfo) => {
+    async (
+      decryptedMessageContent: string,
+      senderInfo: SenderInfo,
+      messageID: string,
+    ) => {
       const parsedMessageToDevice = JSON.parse(decryptedMessageContent);
 
       // Handle user-action messages
@@ -103,7 +107,10 @@
       } else if (
         userActionMessage.type === userActionsP2PMessageTypes.DM_OPERATION
       ) {
-        await processDMOperation(userActionMessage.op);
+        await processDMOperation(userActionMessage.op, {
+          messageID,
+          senderDeviceID: senderInfo.deviceID,
+        });
       } else if (
         userActionMessage.type === userActionsP2PMessageTypes.ACCOUNT_DELETION
       ) {
@@ -253,7 +260,11 @@
           );
 
           try {
-            await handleOlmMessageToDevice(decrypted, message.senderInfo);
+            await handleOlmMessageToDevice(
+              decrypted,
+              message.senderInfo,
+              messageID,
+            );
           } catch (e) {
             console.log('Failed processing Olm P2P message:', e);
           }