diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js
--- a/lib/reducers/message-reducer.js
+++ b/lib/reducers/message-reducer.js
@@ -1929,7 +1929,6 @@
     const messagesResult = mergeUpdatesWithMessageInfos(
       updatedRawMessageInfos,
       updateInfos,
-      {},
     );
 
     const { messageStoreOperations, messageStore: newMessageStore } =
diff --git a/lib/reducers/thread-reducer.js b/lib/reducers/thread-reducer.js
--- a/lib/reducers/thread-reducer.js
+++ b/lib/reducers/thread-reducer.js
@@ -580,7 +580,8 @@
       threadStoreOperations: [],
     };
   } else if (action.type === processDMOpsActionType) {
-    const { updateInfos, rawMessageInfos } = action.payload;
+    const { updateInfos, rawMessageInfos, messagesNotifyTypes } =
+      action.payload;
     if (updateInfos.length === 0 && rawMessageInfos.length === 0) {
       return {
         threadStore: state,
@@ -591,12 +592,13 @@
     const { threadStoreOperations, updatedThreadStore } =
       generateOpsAndProcessThreadUpdates(state, updateInfos);
 
-    const newMessagesUpdates = getThreadUpdatesForNewMessages(
+    const newMessagesUpdates = getThreadUpdatesForNewMessages({
       rawMessageInfos,
       updateInfos,
-      updatedThreadStore.threadInfos,
+      threadInfos: updatedThreadStore.threadInfos,
+      messagesNotifyTypes,
       viewerID,
-    );
+    });
 
     if (newMessagesUpdates.length === 0) {
       return {
diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js
--- a/lib/shared/dm-ops/dm-op-utils.js
+++ b/lib/shared/dm-ops/dm-op-utils.js
@@ -53,6 +53,10 @@
 } from '../../types/update-types.js';
 import { getContentSigningKey } from '../../utils/crypto-utils.js';
 import { useSelector, useDispatch } from '../../utils/redux-utils.js';
+import {
+  type MessageNotifyType,
+  messageNotifyTypes,
+} from '../messages/message-spec.js';
 import { messageSpecs } from '../messages/message-specs.js';
 import {
   expectedAccountDeletionUpdateTimeout,
@@ -404,12 +408,24 @@
   );
 }
 
+type GetThreadUpdatesForNewMessagesInputType = {
+  +rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
+  +updateInfos: $ReadOnlyArray<ClientUpdateInfo>,
+  +threadInfos: RawThreadInfos,
+  +messagesNotifyTypes: { +[messageID: string]: MessageNotifyType },
+  +viewerID: ?string,
+};
 function getThreadUpdatesForNewMessages(
-  rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
-  updateInfos: $ReadOnlyArray<ClientUpdateInfo>,
-  threadInfos: RawThreadInfos,
-  viewerID: ?string,
+  input: GetThreadUpdatesForNewMessagesInputType,
 ): Array<ClientUpdateInfo> {
+  const {
+    rawMessageInfos,
+    updateInfos,
+    threadInfos,
+    messagesNotifyTypes,
+    viewerID,
+  } = input;
+
   if (!viewerID) {
     return [];
   }
@@ -448,16 +464,27 @@
       threadInfo = newThreadInfo;
     }
 
-    const messagesFromOtherPeers = messagesByThreadID[threadID].filter(
-      message => message.creatorID !== viewerID,
+    const messagesAffectingUnreadStatus = messagesByThreadID[threadID].filter(
+      message => {
+        const { id } = message;
+        invariant(id, 'Thick thread RawMessageInfos should always have ID');
+        const messageNotifyType = messagesNotifyTypes[id];
+        return (
+          message.creatorID !== viewerID &&
+          (messageNotifyType === messageNotifyTypes.SET_UNREAD ||
+            messageNotifyType === messageNotifyTypes.NOTIF_AND_SET_UNREAD)
+        );
+      },
     );
-    if (messagesFromOtherPeers.length === 0) {
+    if (messagesAffectingUnreadStatus.length === 0) {
       continue;
     }
     // We take the most recent timestamp to make sure that
     // change_thread_read_status operation older
     // than it won't flip the status to read.
-    const time = Math.max(messagesFromOtherPeers.map(message => message.time));
+    const time = Math.max(
+      messagesAffectingUnreadStatus.map(message => message.time),
+    );
     invariant(threadInfo.thick, 'Thread should be thick');
 
     if (threadInfo.timestamps.currentUser.unread < time) {