# MSC3952: Intentional Mentions Mentioning other users on Matrix is difficult -- it is not possible to know if [mentioning a user by display name or Matrix ID](https://github.com/matrix-org/matrix-spec/issues/353) will count as a mention, but is also too easy to mistakenly mention a user. (Note that throughout this proposal "mention" is considered equivalent to a "ping" or highlight notification.) Some situations that result in unintentional mentions include: * Replying to a message will re-issue pings from the initial message due to [fallback replies](https://spec.matrix.org/v1.5/client-server-api/#fallbacks-for-rich-replies). * A user without the power level to send `@room` can abuse this by including `@room` in a message and getting a user with the appropriate power levels to reply to them. * Each time a message is edited the new version will be re-evaluated for mentions. * Mentions occurring [in spoiler contents](https://github.com/matrix-org/matrix-spec/issues/16) or [code blocks](https://github.com/matrix-org/matrix-spec/issues/15) are evaluated. * If the [localpart of your Matrix ID is a common word](https://github.com/matrix-org/matrix-spec-proposals/issues/3011) then the push rule matching usernames (`.m.rule.contains_user_name`) matches too often (e.g. Travis CI matching if your Matrix ID is `@travis:example.org`). * If the [localpart or display name of your Matrix ID matches the hostname](https://github.com/matrix-org/matrix-spec-proposals/issues/2735) (e.g. `@example:example.org` receives notifications whenever `@foo:example.org` is replied to). As a sender you do not know if including the user's display name or Matrix ID would even be interpreted as a mention (see [issue 353](https://github.com/matrix-org/matrix-spec/issues/353)). This results in some unexpected behavior and bugs: * Matrix users use "leetspeak" when sending messages to avoid mentions (e.g. referring to M4tthew instead of Matthew). * It is impossible to ping one out of multiple people with the same localpart (or display name). * Since the relation between `body` and `formatted_body` is ill-defined and ["pills" are converted to display names](https://github.com/matrix-org/matrix-spec/issues/714), this can result in missed messages. [^1] There are also some other related bugs: * Matrix users will append emoji or other unique text in their display names to avoid unintentional pings. * Bridging mentions is suboptimal since they [use display names](https://github.com/matrix-org/matrix-spec/issues/353#issuecomment-1055809364) as a workaround, e.g.: * It breaks the contract that bridges will not mutate the content of messages. * For some protocols, bridges need try to figure out if every message contains any of the possible nicknames of room members. * If a user changes their display name in a room, [they might not be mentioned unless the historical display name](https://github.com/matrix-org/matrix-spec/issues/353#issuecomment-1055809372) is used while processing push rules. ## Background Mentions are powered by two of the default push rules that search an event's `content.body` property for the current user's display name ([`.m.rule.contains_display_name`](https://spec.matrix.org/v1.5/client-server-api/#default-override-rules)) or the localpart of their Matrix ID ([`.m.rule.contains_user_name`](https://spec.matrix.org/v1.5/client-server-api/#default-content-rules)). There's also a [section about "user and room mentions"](https://spec.matrix.org/v1.5/client-server-api/#user-and-room-mentions) which defines that messages which mention the current user in the `formatted_body` of the message should be colored differently: > If the current user is mentioned in a message (either by a mention as defined > in this module or by a push rule), the client should show that mention differently > from other mentions, such as by using a red background color to signify to the > user that they were mentioned. ## Proposal The existing push rules for user and room mentions are deprecated and new rules, which use a property specific for mentions[^2], are added to make mentions simpler and more reliable for users. ### New event property A new `m.mentions` property is added to the event content; it is an object with two optional properties: * `user_ids`: an array of strings consisting of Matrix IDs to mention. * `room`: a boolean, true indicates an "@room" mention. Any other value or the property missing is interpreted as not an "@room" mention. It is valid to include both the `user_ids` and `room` properties. It is recommended that homeservers reject locally created events with an invalid `m.mentions` property with an error with a status code of `400` and an errcode of `M_INVALID_PARAM`. Clients add a Matrix ID to the `user_ids` array whenever composing a message which includes an intentional mention, such as a ["pill"](https://spec.matrix.org/v1.5/client-server-api/#user-and-room-mentions). Clients set the `room` value to `true` when making a room-wide announcement. Clients should also set these values at other times when it is obvious the user intends to explicitly mention a user.[^3] The `m.mentions` property is part of the plaintext event body and should be encrypted into the ciphertext for encrypted events. ### New push rules Two new default push rule are added. The `.m.rule.is_user_mention` override push rule would appear directly before the `.m.rule.contains_display_name` push rule: ```json { "rule_id": ".m.rule.is_user_mention", "default": true, "enabled": true, "conditions": [ { "kind": "event_property_contains", "key": "content.m\\.mentions.user_ids", "value": "[the user's Matrix ID]" } ], "actions": [ "notify", { "set_tweak": "sound", "value": "default" }, { "set_tweak": "highlight" } ] } ``` (Note: `\\.` would become a single logical backslash followed by a dot since the above is in JSON-representation. See [MSC3873](https://github.com/matrix-org/matrix-spec-proposals/pull/3873).) The `.m.rule.is_room_mention` override push rule would appear directly before the `.m.rule.roomnotif` push rule: ```json { "rule_id": ".m.rule.is_room_mention", "default": true, "enabled": true, "conditions": [ { "kind": "event_property_is", "key": "content.m\\.mentions.room", "value": true }, { "kind": "sender_notification_permission", "key": "room" } ], "actions": [ "notify", { "set_tweak": "highlight" } ] } ``` An example event matching both `.m.rule.is_user_mention` (for `@alice:example.org`) and `.m.rule.is_room_mention` is provided below: ```json { "content": { "body": "This is an example mention @alice:example.org", "format": "org.matrix.custom.html", "formatted_body": "This is an example mention Alice", "msgtype": "m.text", "m.mentions": { "user_ids": ["@alice:example.org"], "room": true } }, "event_id": "$143273582443PhrSn:example.org", "origin_server_ts": 1432735824653, "room_id": "!somewhere:over.the.rainbow", "sender": "@example:example.org", "type": "m.room.message", "unsigned": { "age": 1234 } } ``` ### Client behavior The overall user experience is not modified, beyond improving explicitness and reducing unintended mentions. For example, it is common that a client will show an event with a mention in a different color (and denote the current user's "pill", as a way of showing the user *why* they were mentioned). This behavior is unchanged. There are two variations that clients should take into account when decorating messages for mentions, however: * The presence of a user's "pill" in a message no longer implies it is a mention. * This makes it easier to mention users without including their "pill" in a message (see [Abuse Potential](#abuse-potential) for ideas to combat this). ### Backwards compatibility The [`.m.rule.contains_display_name`](https://spec.matrix.org/v1.5/client-server-api/#default-override-rules), [`.m.rule.contains_user_name`](https://spec.matrix.org/v1.5/client-server-api/#default-content-rules), and [`.m.rule.roomnotif`](https://spec.matrix.org/v1.5/client-server-api/#default-override-rules) push rules are to be deprecated. To avoid unintentional mentions these rules are modified to only apply when the `m.mentions` property is missing; clients should provide at least an empty `m.mentions` property on every message to avoid the unintentional mentions discussed in the introduction. A future room version may wish to disable the legacy push rules: clients would no longer be required to include the `m.mentions` property on every event. It maybe convenient to do this when extensible events are adopted (see [MSC3932](https://github.com/matrix-org/matrix-spec-proposals/pull/3932)). After acceptance, it is likely for there to be disagreement about which push rules are implemented: legacy clients and homeservers may not yet have deprecated the `.m.rule.contains_display_name`, `.m.rule.contains_user_name`, and `.m.rule.roomnotif` push rules, while up-to-date clients and homeservers will support the `.m.rule.is_user_mention` and `.m.rule.is_room_mention` push rules. It is expected that both sets of push rules will need to be supported for a period of time, but at worst case should simply result in the current behavior (documented in the preamble). If users wish to continue to be notified of messages containing their display name it is recommended that clients create a specific keyword rule for this, e.g. a `content` rule of the form: ```json { "actions": [ "notify", { "set_tweak": "sound", "value": "default" }, { "set_tweak": "highlight" } ], "pattern": "alice", "rule_id": "alice", "enabled": true } ``` ### Impact on replies Users are notified of replies via the `.m.rule.contains_display_name` or the `.m.rule.contains_user_name` push rule matching the [rich reply fallback](https://spec.matrix.org/v1.6/client-server-api/#fallbacks-for-rich-replies). Unfortunately these push rules will be disabled for events which contain the `m.mentions` property, i.e. all newly created events (see [above](#backwards-compatibility)). Clients should include the sender of the event being replied to as well as any mentioned users in that event (excluding yourself) in the new event's `m.mentions` property. The `room` property MUST NOT be copied over. This signals that it is the *intention* of the sender to mention all of those people. This behavior may not make sense in all situations (e.g. an email-like client could provide both a "reply" and "reply all", while a microblogging client may wish to provide a "quote reply", dropping all mentions from the original event) and clients may wish to allow users to modify the list of mentioned users. For example, if there is an event: ```json5 { "sender": "@dan:example.org", "event_id": "$initial_event", "content": { "body": "Alice: Have you heard from Bob?", "m.mentions": { "user_ids": ["@alice:example.org", "@bob:example.org"] } }, // other fields as required by events } ``` And a reply from Alice: ```json5 { "content": { "body": "> <@dan:example.org> Alice: Have you heard from Bob?\n\nNo, but I saw him with Charlie earlier.", "m.mentions": { "user_ids": [ // Include the sender of $initial_event (optional). "@dan:example.org", // The users mentioned, minus yourself (optional). "@bob:example.org", // New mentions, as normal. "@charlie:example.org" ] }, "m.relates_to": { "m.in_reply_to": { "event_id": "$initial_event" } } }, // other fields as required by events } ``` If a user wishes to be notified of *all replies* to their messages, other solutions should be investigated, such as [MSC3664](https://github.com/matrix-org/matrix-spec-proposals/pull/3664). This would give more equal power to both senders and receivers of events. ### Impact on edits Similarly to [replies](#impact-on-replies), users are notified of message edits via the `.m.rule.contains_display_name` or the `.m.rule.contains_user_name` push rule matching the [fallback content](https://spec.matrix.org/v1.6/client-server-api/#event-replacements). Generally this is undesirable and users do not need to be notified for the same message multiple times (e.g. if a user is fixing a typo). Replacement events may have `m.mentions` properties in two locations: * One at the top-level of the `content`, which should contain any users to mention *for this edit*. * One inside the `m.new_content` property, which should contain the full list of mentioned users in any version of the event, unless a mention is removed (see below). It is recommended that clients use an empty top-level `m.mentions` property when editing an event, *unless* the edit is significant or if additional users are mentioned in the latest version. For example, if there is an event: ```json5 { "sender": "@dan:example.org", "event_id": "$initial_event", "content": { "body": "Hello Alice!", "m.mentions": { "user_ids": ["@alice:example.org"] } }, // other fields as required by events } ``` And an edit after realizing that Bob is also in the room: ```json5 { "content": { "body": "* Hello Alice & Bob!", "m.mentions": { "user_ids": [ // Include only the newly mentioned user. "@bob:example.org" ] }, "m.new_content": { "body": "Hello Alice & Bob!", "m.mentions": { "user_ids": [ // Include all mentioned users. "@alice:example.org", "@bob:example.org" ] }, }, "m.relates_to": { "rel_type": "m.replace", "event_id": "$initial_event" } }, // other fields as required by events } ``` Mentions can also be removed as part of an edit. In this case, the top-level `m.mentions` property would not include the removed user IDs (you cannot cancel the notification from the previous event) or any previously notified users, and the removed user would also be removed from the `m.new_content` proprerty's copy of `m.mentions`. This should limit duplicate, unnecessary notifications for users. If a user wishes to receive notifications for edits of events they were mentioned in then they could setup a push rule for the `content.m\\.new_content.m\\.mentions` property or potentially leverage [MSC3664](https://github.com/matrix-org/matrix-spec-proposals/pull/3664). This implies that: * If a client highlights a message visually (e.g. by coloring it red), then it should look at the `m.mentions` under `m.new_content` for edited messages. Otherwise, in the example above, Alice would not see the message as red, even though the intent was for her to be mentioned. * Any sort of processing of push rules, e.g. to display a notification (sound, toast, push notification), should occur without any special rules. I.e. the `.m.rule.is_user_mention` and `.m.rule.is_room_mention` should look at the `m.mentions` directly under `content` and not match for Alice. ### Impact on bridging For protocols with a similar mechanism for listing mentioned users this should strengthen the bridging contract as it enables bridges to stop mutating the content of messages. The bridge should be able to map from the remote user ID to the bridged user ID and include that in the `m.mentions` property of the Matrix event & the proper field in the bridged protocol[^4]. For bridged protocols that do not have this mechanism, the bridge will only be able to stop mutating content on messages bridged *into* Matrix. Messages bridged out of Matrix will still need to embed the mention into the text content.[^5] ## Potential issues ### Abuse potential This proposal makes it trivial to "hide" mentions since it does not require the mentioned Matrix IDs to be part of the displayed text. This is only a limitation for current clients: mentions could be exposed in the user interface directly. For example, a de-emphasized "notified" list could be shown on messages, similar to CCing users on an e-mail. Although not including mentions in the displayed text could be used as an abuse vector, it does not enable additional malicious behavior than what is possible today. From discussions and research while writing this MSC there are moderation benefits to using a separate property for mentions: * The number of mentions is trivially limited by moderation tooling, e.g. it may be appropriate for a community room to only allow 10 mentions. Events not abiding by this could be rejected automatically (or users could be banned automatically). * Various forms of "mention bombing" are no longer possible. * It is simpler to collect metrics on how mentions are being used (it is no longer necessary to process the textual `body` for every user's display name and local part). Overall this proposal seems to be neutral or positive in the ability to combat malicious behavior. ### Encrypted mentions & `/notifications` A previous version of this proposal (and the alternative [MSC1796](https://github.com/matrix-org/matrix-spec-proposals/pull/1796)) suggested leaving the `m.mentions` property in cleartext. This was [deemed too large of a metadata leak](https://github.com/matrix-org/matrix-spec-proposals/pull/3952#discussion_r1112154200) and removed from this proposal (and MSC1796 was closed). A downside of this is that homeservers (still) will not be able to differentiate between notifications and mentions in many cases. This mostly affects how often homeservers push to devices (see [MSC3996](https://github.com/matrix-org/matrix-spec-proposals/pull/3996) for more information), but also means that the `/notifications?only=highlight` API is not useful in encrypted rooms. ## Future extensions ### Combating abuse Some ideas for combating abuse came from our discussion and research which are worth sharing. These ideas are not a requirement for implementing this MSC, and generally do not depend on it. (They could be implemented today with enough effort.) It was recommended that clients could expose *why* an event has caused a notification and give users inline tools to combat abuse. For example, a client might show a tooltip: > The sender of the message (`@alice:example.org`) mentioned you in this event. > > Block `@alice:example.org` from sending you messages? `[Yes]` `[No]` Additionally, if a user sending a message is about to mention many people it can be useful to confirm whether they wish to do that (or prompt them to do an `@room` mention instead). Moderators may find tooling to quickly find messages which mention many users useful in combating mention spammers. (Note that this should be made easier by this MSC.) A future MSC might wish to explore features for trusted contacts or soft-ignores to give users more control over who can generate notifications. ### Muted except for mentions push rules It might be desirable to have a "muted-except-for-mentions" feature for large (encrypted) rooms. This is particularly useful on iOS where a push notification can be decrypted via a background process but *cannot* be suppressed. This means it is not possible for the client to handle this feature and it must be handled on the server, unfortunately this would not be possible with the current proposal since the `m.mentions` property is encrypted (and the server cannot act on it). Solving this problem is left to a future MSC, such as [MSC3996](https://github.com/matrix-org/matrix-spec-proposals/pull/3996) which builds on this proposal. ### Pillifying `@room` Some clients attempt to create a "pill" out of `@room` mentions, but this is not a requirement of the Matrix specification. The current [user and rooms mentions](https://spec.matrix.org/v1.5/client-server-api/#user-and-room-mentions) section could be expanded for this situation. ### Extensible events Handling of this property in [MSC1767](https://github.com/matrix-org/matrix-doc/pull/1767)-style extensible events is deliberately left for a future MSC to address, if needed. ### Role mentions It is possible to add additional properties to the `m.mentions` object, e.g. a foreseeable usecase would be a `roles` property which could include values such as `admins` or `mods`. Defining this in detail is left to a future MSC. ### Cancelling notifications It might be useful for a future MSC to investigate cancelling notifications if a user's mention is removed while [editing events](#impact-on-edits). This could be quite difficult as it is unclear if the mentioned user has already received the notification or not. ## Alternatives ### Prior proposals There are a few prior proposals which tackle subsets of the above problem: * [MSC1796](https://github.com/matrix-org/matrix-spec-proposals/pull/1796): similar to the proposal in this MSC, but limited to encrypted events (and kept in cleartext). * [MSC2463](https://github.com/matrix-org/matrix-spec-proposals/pull/2463): excludes searching inside a Matrix ID for localparts / display names of other users. * [MSC3517](https://github.com/matrix-org/matrix-spec-proposals/pull/3517): searches for Matrix IDs (instead of display name / localpart) and only searches specific event types & properties. * [Custom push rules](https://o.librepush.net/aux/matrix_reitools/pill_mention_rules.html) to search for matrix.to links instead of display name / localpart.
The above generates a new push rule to replace `.m.rule.contains_display_name` and `.m.rule.contains_user_name`: ```json { "conditions": [ { "kind": "event_match", "key": "content.formatted_body", "pattern": "*https://matrix.to/#/@alice:example.org*" } ], "actions" : [ "notify", { "set_tweak": "sound", "value": "default" }, { "set_tweak": "highlight" } ] } ```
The last two proposals use a similar idea of attempting to find "pills" in the `formatted_body`, this has some downsides though: * It doesn't allow for hidden mentions, which can be useful in some situations. * It does not work for event types other than `m.room.message`. It also adds significant implementation complexity since the HTML messages must now be parsed for notifications. This is expensive and introduces potential security issues. ### Room version for backwards compatibility Alternative backwards compatibility suggestions included using a new room version, similar to [MSC3932](https://github.com/matrix-org/matrix-spec-proposals/pull/3932) for extensible events. This does not seem like a good fit since room versions are not usually interested in non-state events. It would additionally require a stable room version before use, which would unnecessarily delay usage. Another MSC can address this concern, such as in the extensible events series, if desirable to be gated by a room version for a "clean slate" approach. ## Security considerations None not already described. ## Unstable prefix During development the following mapping will be used: | What | Stable | Unstable | |---------------------|-------------------|--------------------------------------| | Event property | `m.mentions` | `org.matrix.msc3952.mentions` | | Push rule ID | `.m.rule.*` | `.org.matrix.msc3952.*` | The server will include the `org.matrix.msc3952_intentional_mentions` flag in the `unstable_features` array of the `/versions` endpoint. If a client sees this flag it can choose to apply the deprecation logic discussed in the [backwards compatibility](#backwards-compatibility) section. ## Dependencies This depends on the following (accepted) MSCs: * [MSC3758](https://github.com/matrix-org/matrix-spec-proposals/pull/3758): Add `event_property_is` push rule condition kind * [MSC3873](https://github.com/matrix-org/matrix-spec-proposals/pull/3873): event_match dotted keys * [MSC3966](https://github.com/matrix-org/matrix-spec-proposals/pull/3966): `event_property_contains` push rule condition [^1]: It is [defined as](https://spec.matrix.org/v1.5/client-server-api/#mroommessage-msgtypes) the the "plain text version of the HTML [`formatted_body`] should be provided in the `body`", but there is no particular algorithm to convert from HTML to plain text *except* when converting mentions, where the [plain text version uses the link anchor, not the link](https://spec.matrix.org/v1.5/client-server-api/#client-behaviour-26). [^2]: As proposed in [issue 353](https://github.com/matrix-org/matrix-spec/issues/353). [^3]: Note that this isn't really a change in behavior, it is just making the behavior explicit. It is expected that users already considered "pilled" users to be mentions, and it was more unexpected when non-pilled users *were* mentioned. This MSC fixes the latter case. [^4]: Some protocols which provide structured data for mentions include [Twitter](https://developer.twitter.com/en/docs/twitter-api/data-dictionary/object-model/tweet), [Mastodon](https://docs.joinmastodon.org/entities/Status/#Mention), [Discord](https://discord.com/developers/docs/resources/channel#message-object), and [Microsoft Teams](https://learn.microsoft.com/en-us/graph/api/resources/chatmessagemention?view=graph-rest-1.0). [^5]: Unfortunately some protocols do *not* provide structured data: the message itself must be parsed for mentions, e.g. IRC or [Slack](https://api.slack.com/reference/surfaces/formatting#mentioning-users).