diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue
index 1ef3f4338..4ad3d2d89 100644
--- a/src/client/components/note-detailed.vue
+++ b/src/client/components/note-detailed.vue
@@ -350,7 +350,15 @@ export default defineComponent({
 
 		capture(withHandler = false) {
 			if (this.$i) {
-				this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+				this.connection.send('sn', { id: this.appearNote.id });
+				if (this.appearNote.userId !== this.$i.id) {
+					if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) {
+						this.connection.send('readMention', { id: this.appearNote.id });
+					}
+					if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) {
+						this.connection.send('readSpecifiedNote', { id: this.appearNote.id });
+					}
+				}
 				if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
 			}
 		},
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 65e09b780..3b59afd71 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -325,7 +325,15 @@ export default defineComponent({
 
 		capture(withHandler = false) {
 			if (this.$i) {
-				this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+				this.connection.send('sn', { id: this.appearNote.id });
+				if (this.appearNote.userId !== this.$i.id) {
+					if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) {
+						this.connection.send('readMention', { id: this.appearNote.id });
+					}
+					if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) {
+						this.connection.send('readSpecifiedNote', { id: this.appearNote.id });
+					}
+				}
 				if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
 			}
 		},
diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue
index 5a4a13d88..29bc61d9c 100644
--- a/src/client/ui/chat/note.vue
+++ b/src/client/ui/chat/note.vue
@@ -325,7 +325,15 @@ export default defineComponent({
 
 		capture(withHandler = false) {
 			if (this.$i) {
-				this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+				this.connection.send('sn', { id: this.appearNote.id });
+				if (this.appearNote.userId !== this.$i.id) {
+					if (this.appearNote.mentions && this.appearNote.mentions.includes(this.$i.id)) {
+						this.connection.send('readMention', { id: this.appearNote.id });
+					}
+					if (this.appearNote.visibleUserIds && this.appearNote.visibleUserIds.includes(this.$i.id)) {
+						this.connection.send('readSpecifiedNote', { id: this.appearNote.id });
+					}
+				}
 				if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
 			}
 		},
diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts
index 8a9d295d3..1e3014bd4 100644
--- a/src/server/api/endpoints/notes/mentions.ts
+++ b/src/server/api/endpoints/notes/mentions.ts
@@ -1,12 +1,12 @@
 import $ from 'cafy';
 import { ID } from '../../../../misc/cafy-id';
 import define from '../../define';
-import read from '../../../../services/note/read';
 import { Notes, Followings } from '../../../../models';
 import { generateVisibilityQuery } from '../../common/generate-visibility-query';
 import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
 import { makePaginationQuery } from '../../common/make-pagination-query';
 import { Brackets } from 'typeorm';
+import { readMention } from '../../../../services/note/read-mention';
 
 export const meta = {
 	desc: {
@@ -79,9 +79,7 @@ export default define(meta, async (ps, user) => {
 
 	const mentions = await query.take(ps.limit!).getMany();
 
-	for (const note of mentions) {
-		read(user.id, note.id);
-	}
+	readMention(user.id, mentions.map(n => n.id));
 
 	return await Notes.packMany(mentions, user);
 });
diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts
index bb37cfa62..4a87f61e7 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -2,7 +2,6 @@ import autobind from 'autobind-decorator';
 import * as websocket from 'websocket';
 import { readNotification } from '../common/read-notification';
 import call from '../call';
-import readNote from '../../../services/note/read';
 import Channel from './channel';
 import channels from './channels';
 import { EventEmitter } from 'events';
@@ -14,6 +13,8 @@ import { AccessToken } from '../../../models/entities/access-token';
 import { UserProfile } from '../../../models/entities/user-profile';
 import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '../../../services/stream';
 import { UserGroup } from '../../../models/entities/user-group';
+import { readMention } from '../../../services/note/read-mention';
+import { readSpecifiedNote } from '../../../services/note/read-specified-note';
 
 /**
  * Main stream connection
@@ -86,9 +87,10 @@ export default class Connection {
 		switch (type) {
 			case 'api': this.onApiRequest(body); break;
 			case 'readNotification': this.onReadNotification(body); break;
-			case 'subNote': this.onSubscribeNote(body, true); break;
-			case 'sn': this.onSubscribeNote(body, true); break; // alias
-			case 's': this.onSubscribeNote(body, false); break;
+			case 'readMention': this.onReadMention(body); break;
+			case 'readSpecifiedNote': this.onReadSpecifiedNote(body); break;
+			case 'subNote': this.onSubscribeNote(body); break;
+			case 'sn': this.onSubscribeNote(body); break; // alias
 			case 'unsubNote': this.onUnsubscribeNote(body); break;
 			case 'un': this.onUnsubscribeNote(body); break; // alias
 			case 'connect': this.onChannelConnectRequested(body); break;
@@ -141,11 +143,31 @@ export default class Connection {
 		readNotification(this.user!.id, [payload.id]);
 	}
 
+	@autobind
+	private onReadMention(payload: any) {
+		if (!payload.id) return;
+		if (this.user) {
+			// TODO: ある程度まとめてreadMentionするようにする
+			// 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadMentionに渡すような実装にする
+			readMention(this.user.id, [payload.id]);
+		}
+	}
+
+	@autobind
+	private onReadSpecifiedNote(payload: any) {
+		if (!payload.id) return;
+		if (this.user) {
+			// TODO: ある程度まとめてreadSpecifiedNoteするようにする
+			// 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadSpecifiedNoteに渡すような実装にする
+			readSpecifiedNote(this.user.id, [payload.id]);
+		}
+	}
+
 	/**
 	 * 投稿購読要求時
 	 */
 	@autobind
-	private onSubscribeNote(payload: any, read: boolean) {
+	private onSubscribeNote(payload: any) {
 		if (!payload.id) return;
 
 		if (this.subscribingNotes[payload.id] == null) {
@@ -157,12 +179,6 @@ export default class Connection {
 		if (this.subscribingNotes[payload.id] === 1) {
 			this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage);
 		}
-
-		if (this.user && read) {
-			// TODO: クライアントでタイムライン読み込みなどすると、一度に大量のreadNoteが発生しクエリ数がすごいことになるので、ある程度まとめてreadNoteするようにする
-			// 具体的には、この箇所ではキュー的な配列にread予定ノートを溜めておくに留めて、別の箇所で定期的にキューにあるノートを配列でreadNoteに渡すような実装にする
-			readNote(this.user.id, payload.id);
-		}
 	}
 
 	/**
diff --git a/src/services/note/read-mention.ts b/src/services/note/read-mention.ts
new file mode 100644
index 000000000..2a668ecd6
--- /dev/null
+++ b/src/services/note/read-mention.ts
@@ -0,0 +1,29 @@
+import { publishMainStream } from '../stream';
+import { Note } from '../../models/entities/note';
+import { User } from '../../models/entities/user';
+import { NoteUnreads } from '../../models';
+import { In } from 'typeorm';
+
+/**
+ * Mark a mention note as read
+ */
+export async function readMention(
+	userId: User['id'],
+	noteIds: Note['id'][]
+) {
+	// Remove the records
+	await NoteUnreads.delete({
+		userId: userId,
+		noteId: In(noteIds),
+	});
+
+	const mentionsCount = await NoteUnreads.count({
+		userId: userId,
+		isMentioned: true
+	});
+
+	if (mentionsCount === 0) {
+		// 全て既読になったイベントを発行
+		publishMainStream(userId, 'readAllUnreadMentions');
+	}
+}
diff --git a/src/services/note/read-specified-note.ts b/src/services/note/read-specified-note.ts
new file mode 100644
index 000000000..0fcb66bf9
--- /dev/null
+++ b/src/services/note/read-specified-note.ts
@@ -0,0 +1,29 @@
+import { publishMainStream } from '../stream';
+import { Note } from '../../models/entities/note';
+import { User } from '../../models/entities/user';
+import { NoteUnreads } from '../../models';
+import { In } from 'typeorm';
+
+/**
+ * Mark a specified note as read
+ */
+export async function readSpecifiedNote(
+	userId: User['id'],
+	noteIds: Note['id'][]
+) {
+	// Remove the records
+	await NoteUnreads.delete({
+		userId: userId,
+		noteId: In(noteIds),
+	});
+
+	const specifiedCount = await NoteUnreads.count({
+		userId: userId,
+		isSpecified: true
+	});
+
+	if (specifiedCount === 0) {
+		// 全て既読になったイベントを発行
+		publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
+	}
+}
diff --git a/src/services/note/read.ts b/src/services/note/read.ts
deleted file mode 100644
index 5a39ab30b..000000000
--- a/src/services/note/read.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { publishMainStream } from '../stream';
-import { Note } from '../../models/entities/note';
-import { User } from '../../models/entities/user';
-import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models';
-import { Not, IsNull } from 'typeorm';
-
-/**
- * Mark a note as read
- */
-export default async function(
-	userId: User['id'],
-	noteId: Note['id']
-) {
-	async function careNoteUnreads() {
-		const exist = await NoteUnreads.findOne({
-			userId: userId,
-			noteId: noteId,
-		});
-
-		if (!exist) return;
-
-		// Remove the record
-		await NoteUnreads.delete({
-			userId: userId,
-			noteId: noteId,
-		});
-
-		if (exist.isMentioned) {
-			NoteUnreads.count({
-				userId: userId,
-				isMentioned: true
-			}).then(mentionsCount => {
-				if (mentionsCount === 0) {
-					// 全て既読になったイベントを発行
-					publishMainStream(userId, 'readAllUnreadMentions');
-				}
-			});
-		}
-
-		if (exist.isSpecified) {
-			NoteUnreads.count({
-				userId: userId,
-				isSpecified: true
-			}).then(specifiedCount => {
-				if (specifiedCount === 0) {
-					// 全て既読になったイベントを発行
-					publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
-				}
-			});
-		}
-
-		if (exist.noteChannelId) {
-			NoteUnreads.count({
-				userId: userId,
-				noteChannelId: Not(IsNull())
-			}).then(channelNoteCount => {
-				if (channelNoteCount === 0) {
-					// 全て既読になったイベントを発行
-					publishMainStream(userId, 'readAllChannels');
-				}
-			});
-		}
-	}
-
-	async function careAntenna() {
-		const beforeUnread = await Users.getHasUnreadAntenna(userId);
-		if (!beforeUnread) return;
-
-		const antennas = await Antennas.find({ userId });
-
-		await Promise.all(antennas.map(async antenna => {
-			const countBefore = await AntennaNotes.count({
-				antennaId: antenna.id,
-				read: false
-			});
-
-			if (countBefore === 0) return;
-
-			await AntennaNotes.update({
-				antennaId: antenna.id,
-				noteId: noteId
-			}, {
-				read: true
-			});
-
-			const countAfter = await AntennaNotes.count({
-				antennaId: antenna.id,
-				read: false
-			});
-
-			if (countAfter === 0) {
-				publishMainStream(userId, 'readAntenna', antenna);
-			}
-		}));
-
-		Users.getHasUnreadAntenna(userId).then(unread => {
-			if (!unread) {
-				publishMainStream(userId, 'readAllAntennas');
-			}
-		});
-	}
-
-	careNoteUnreads();
-	careAntenna();
-}