|
| 1 | +--- |
| 2 | +title: Targeted Messages |
| 3 | +description: Learn about enabling targeted messages for agents in Teams. |
| 4 | +ms.localizationpriority: high |
| 5 | +ms.date: 02/06/2025 |
| 6 | +ms.topic: reference |
| 7 | +--- |
| 8 | + |
| 9 | +<!-- markdownlint-disable MD023 --> |
| 10 | +<!-- markdownlint-disable MD001 --> |
| 11 | +<!-- markdownlint-disable MD024 --> |
| 12 | + |
| 13 | +# Enable targeted messages for agents |
| 14 | + |
| 15 | +> [!NOTE] |
| 16 | +> |
| 17 | +> Support for targeted messages is available in [public developer preview](../resources/dev-preview/developer-preview-intro.md). |
| 18 | +
|
| 19 | +Use targeted messages in your agents or bots to send temporary, private messages to a specific user in a channel, group, or meeting chat. You can also enable an agent or bot to edit or delete targeted messages it sends in a conversation. |
| 20 | + |
| 21 | +**Key points**: |
| 22 | + |
| 23 | +- **About targeted messages** |
| 24 | + - [What is a targeted message](#what-is-a-targeted-message) |
| 25 | + - [Why use targeted messages](#why-use-targeted-messages) |
| 26 | +- **Enable targeted messages** |
| 27 | + - [Send a targeted message](#send-a-targeted-message) |
| 28 | + - [Update a targeted message](#update-a-targeted-message) |
| 29 | + - [Delete a targeted message](#delete-a-targeted-message) |
| 30 | + - [Handle errors](#handle-errors) |
| 31 | + |
| 32 | +## What is a targeted message |
| 33 | + |
| 34 | +A targeted message lets an agent or a bot send a user-targeted message. It supports all [message capabilities](../bots/build-conversational-capability.md#message-content) like buttons, images, Adaptive Cards, and files, and keeps shared conversations uncluttered. Targeted messages are: |
| 35 | + |
| 36 | +- Delivered to only one user in a group context. |
| 37 | +- Auto-purged from clients in 24 hours but might be retained in secure storage based on organizational policy. |
| 38 | +- Restricted for user actions such as reaction, replies, and forwarding. |
| 39 | + |
| 40 | + :::image type="content" source="../assets/images/agents-in-teams/targeted-messages/targeted-messages.png" alt-text="Image shows user scenarios for targeted messages" border="false" lightbox="../assets/images/agents-in-teams/targeted-messages/targeted-messages-main.png"::: |
| 41 | + |
| 42 | +To recipients, they appear like normal inline chat messages, tagged **Only you can see this message**. |
| 43 | + |
| 44 | +> [!NOTE] |
| 45 | +> When you include Adaptive Cards in a targeted message, ensure that user action on the card must not inadvertently create a public response. |
| 46 | +
|
| 47 | +<br> |
| 48 | +Some common user scenarios include: |
| 49 | + |
| 50 | +| Scenario | Use for ... | To ... | |
| 51 | +| --- | --- | --- | |
| 52 | +| AI or Copilot summary | Sharing discussion details for long-running chats for a new participant | Avoid derailing ongoing discussion. | |
| 53 | +| Support messages | Sending user-specific support messages | Send personal reminders, onboarding messages, and quick check-ins without public callouts or spamming the group. | |
| 54 | + |
| 55 | +## Why use targeted messages |
| 56 | + |
| 57 | +Targeted messages are ideal for contextual information or assistance. Among other benefits, targeted messages enhance user experience as follows: |
| 58 | + |
| 59 | +- **Human-in-the-loop scenarios**: <br> |
| 60 | + It's useful for scenarios such as approvals, or informational messages. It lets a user progress through a conversation or a workflow without switching context or seeking help elsewhere. |
| 61 | + |
| 62 | +- **Enhanced user experience**: <br> |
| 63 | + A clear message hierarchy that shows only the content that's meant for everyone is permanent in the chat. |
| 64 | +- **Real-time interaction**: <br> |
| 65 | + Prompt responses from the agent to the user's requirement in the group setting reinforce that the agent is alert to user actions. |
| 66 | + |
| 67 | +## Targeted message developer experience |
| 68 | + |
| 69 | +You can enable targeted messages using Teams SDK or REST APIs. Teams SDK supports C#, TypeScript, and Python (developer preview). You can enable your agent or bot to send, edit, and remove targeted messages in a conversation. |
| 70 | + |
| 71 | +### Send a targeted message |
| 72 | + |
| 73 | +Sending a targeted message is similar to sending a regular message. Only an agent or a bot can send a targeted message. The agent indicates that the message is intended for a specific user in the conversation, and the platform delivers it to that user. The agent doesn't initiate a separate conversation or create a new chat. |
| 74 | + |
| 75 | +Key steps for enabling the agent to send a targeted message are as follows: |
| 76 | + |
| 77 | +1. Determine when a targeted message is appropriate: |
| 78 | + |
| 79 | + Use a targeted message when the response is for one person, or when sharing it with others would add noise, distraction, or confusion. Common characteristics of these scenarios include (but aren't limited to): |
| 80 | + |
| 81 | + - The agent's response is relevant only to the user who initiated the interaction. |
| 82 | + - The agent must respond proactively and in context to a specific user’s message or state. |
| 83 | + - The agent is sharing a personalized recommendation, insight, or follow-up that isn’t relevant to others in the thread or channel. |
| 84 | + |
| 85 | +2. Use any of the following code snippets to send a targeted message: |
| 86 | + |
| 87 | + # [C#](#tab/dotnet1) |
| 88 | + |
| 89 | + ```csharp |
| 90 | + app.OnMessage(async context => |
| 91 | + { |
| 92 | + // Using WithRecipient with isTargeted=true explicitly targets the specified recipient |
| 93 | + await context.Send( |
| 94 | + new MessageActivity("This message is only visible to you!") |
| 95 | + .WithRecipient(context.Activity.From, isTargeted: true) |
| 96 | + ); |
| 97 | + }); |
| 98 | + ``` |
| 99 | + |
| 100 | + For more information, see [Teams SDK](/microsoftteams/platform/teams-ai-library/essentials/sending-messages/overview?pivots=csharp#targeted-messages). |
| 101 | + |
| 102 | + # [TypeScript](#tab/ts1) |
| 103 | + |
| 104 | + ```typescript |
| 105 | + import { MessageActivity } from '@microsoft/teams.api'; |
| 106 | + |
| 107 | + app.on('message', async ({ send, activity }) => { |
| 108 | + // Using withRecipient with isTargeted=true explicitly targets the specified recipient |
| 109 | + await send( |
| 110 | + new MessageActivity('This message is only visible to you!') |
| 111 | + .withRecipient(activity.from, true) |
| 112 | + ); |
| 113 | + }); |
| 114 | + ``` |
| 115 | + |
| 116 | + For more information, see [Teams SDK](/microsoftteams/platform/teams-ai-library/essentials/sending-messages/overview?pivots=typescript#targeted-messages). |
| 117 | + |
| 118 | + # [Python](#tab/Py1) |
| 119 | + |
| 120 | + ```python |
| 121 | + from microsoft_teams.api import MessageActivity, MessageActivityInput |
| 122 | + from microsoft_teams.apps import ActivityContext |
| 123 | + |
| 124 | + @app.on_message |
| 125 | + async def handle_message(ctx: ActivityContext[MessageActivity]): |
| 126 | + # Using with_recipient with is_targeted=True explicitly targets the specified recipient |
| 127 | + await ctx.send( |
| 128 | + MessageActivityInput(text="This message is only visible to you!") |
| 129 | + .with_recipient(ctx.activity.from_, is_targeted=True) |
| 130 | + ) |
| 131 | + ``` |
| 132 | + |
| 133 | + For more information, see [Teams SDK](/microsoftteams/platform/teams-ai-library/essentials/sending-messages/overview?pivots=python#targeted-messages). |
| 134 | + |
| 135 | + # [HTTP](#tab/api1) |
| 136 | + |
| 137 | + Include the 'targeted' designation in the `Send TM` API. |
| 138 | + |
| 139 | + ```REST |
| 140 | + POST {cloud}/v3/conversations/{conversationId}/activities?isTargetedActivity=true |
| 141 | + Authorization: Bearer eyJhbGciOiJIUzI1Ni... |
| 142 | + Content-Type: application/json |
| 143 | + { |
| 144 | + "type": "message", |
| 145 | + "from": { |
| 146 | + "id": "28:c9e...", |
| 147 | + "name": "Contoso" |
| 148 | + }, |
| 149 | + "conversation": { |
| 150 | + "id":"x:17I0...", |
| 151 | + "name": "Convo1" |
| 152 | + }, |
| 153 | + "recipient": { |
| 154 | + "id": "29:1XJ...", |
| 155 | + "name": "Megan Bowen" |
| 156 | + }, |
| 157 | + "text": "My bot's reply" |
| 158 | + } |
| 159 | + ``` |
| 160 | + |
| 161 | + Ensure that you specify the following when the agent sends the message: |
| 162 | + |
| 163 | +- To send a targeted activity, ensure that you indicate the `isTargetedActivity` as `true`. |
| 164 | +- The conversation (chat or channel) ID and targeted user’s ID (Principal ID or MRI). The intended user must be a member of the chat or channel to receive a targeted message. |
| 165 | +- A flag or API call that marks the message as targeted or ephemeral. |
| 166 | + |
| 167 | + Use the service URL from the conversation. The `userId` is the user’s Teams ID (MRI) to target, and `conversationId` is the group chat or channel thread ID. The POST payload is the activity (message) to send, same as for a standard message activity. |
| 168 | + |
| 169 | +### Update a targeted message |
| 170 | + |
| 171 | +The agent can edit the original targeted message if needed. The updated message appears only in the intended user’s view. |
| 172 | + |
| 173 | +Use one of the following code snippets to edit targeted message: |
| 174 | + |
| 175 | +# [C#](#tab/dotnet1) |
| 176 | + |
| 177 | +```csharp |
| 178 | +// Update |
| 179 | +var response = await context.Send( |
| 180 | + new MessageActivity("Original targeted message") |
| 181 | + .WithRecipient(context.Activity.From, true), cancellationToken); |
| 182 | +var conversationId = context.Activity.Conversation.Id; |
| 183 | +var messageId = response.Id; |
| 184 | + |
| 185 | +var updatedMessage = new MessageActivity("This message has been updated!"); |
| 186 | +await context.Api.Conversations.Activities.UpdateTargetedAsync(conversationId, messageId, updatedMessage); |
| 187 | +``` |
| 188 | + |
| 189 | +# [TypeScript](#tab/ts1) |
| 190 | + |
| 191 | +```typescript |
| 192 | +// Update |
| 193 | +const response = await context.send( |
| 194 | + new MessageActivity('Original targeted message') |
| 195 | + .withRecipient(context.activity.from, true), cancellationToken); |
| 196 | +const conversationId = context.activity.conversation.id; |
| 197 | +const messageId = response.id; |
| 198 | + |
| 199 | +const updatedMessage = new MessageActivity('This message has been updated!'); |
| 200 | +await api.conversations.activities.updateTargeted(conversationId, messageId, updatedMessage); |
| 201 | +``` |
| 202 | + |
| 203 | +# [Python](#tab/Py1) |
| 204 | + |
| 205 | +```python |
| 206 | +# Update |
| 207 | +response = await ctx.send( |
| 208 | + MessageActivityInput(text="Original targeted message") |
| 209 | + .with_recipient(ctx.activity.from_property, True), cancellation_token) |
| 210 | +conversation_id = ctx.activity.conversation.id |
| 211 | +message_id = response.id |
| 212 | + |
| 213 | +updated_message = MessageActivityInput(text="This message has been updated!") |
| 214 | +await ctx.api.conversations.activities.update_targeted(conversation_id, message_id, updated_message) |
| 215 | +``` |
| 216 | + |
| 217 | +# [HTTP](#tab/api1) |
| 218 | + |
| 219 | +The agent calls the `Edit TM` API using the message’s `activityId`. |
| 220 | + |
| 221 | +```REST |
| 222 | +PUT {cloud}/v3/conversations/{conversationId}/activities?isTargetedActivity=true |
| 223 | +PUT {cloud}/v3/conversations/{conversationId}/activities/{activityId}?isTargetedActivity=true |
| 224 | +Authorization: Bearer eyJh... |
| 225 | +Content-Type: application/json |
| 226 | +{ |
| 227 | + "type": "message", |
| 228 | + "text": "This message has been updated" |
| 229 | +} |
| 230 | +``` |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +### Delete a targeted message |
| 235 | + |
| 236 | +Agents can delete messages within 24 hours if they've been acted on or they are no longer relevant. Messages are automatically purged from clients after 24 hours. |
| 237 | + |
| 238 | +Use one of the following code snippets to delete targeted message: |
| 239 | + |
| 240 | +# [C#](#tab/dotnet1) |
| 241 | + |
| 242 | +```csharp |
| 243 | +// Delete |
| 244 | +await context.Api.Conversations.Activities.DeleteTargetedAsync(conversationId, messageId); |
| 245 | +``` |
| 246 | + |
| 247 | +# [TypeScript](#tab/ts1) |
| 248 | + |
| 249 | +```typescript |
| 250 | +// Delete |
| 251 | +await api.conversations.activities.deleteTargeted(conversationId, messageId); |
| 252 | +``` |
| 253 | + |
| 254 | +# [Python](#tab/Py1) |
| 255 | + |
| 256 | +```python |
| 257 | +#Delete |
| 258 | +await ctx.api.conversations.activities.delete_targeted(conversation_id, message_id) |
| 259 | +``` |
| 260 | + |
| 261 | +# [HTTP](#tab/api1) |
| 262 | + |
| 263 | +Use the delete message API for enabling the agent to remove targeted messages. It avoids leaving stale content. |
| 264 | + |
| 265 | +```REST |
| 266 | +DELETE {cloud}/v3/conversations/{conversationId}/activities?isTargetedActivity=true |
| 267 | +DELETE {cloud}/v3/conversations/{conversationId}/activities/{activityId}?isTargetedActivity=true |
| 268 | +Authorization: Bearer eyJh... |
| 269 | +Content-Type: application/json |
| 270 | +
|
| 271 | +No body required. |
| 272 | +``` |
| 273 | + |
| 274 | +--- |
| 275 | + |
| 276 | +## Handle errors |
| 277 | + |
| 278 | +After the agent sends a targeted message using Teams SDK or REST APIs, it receives one of the following responses: |
| 279 | + |
| 280 | +- If successful, the targeted user gets the message sent by the agent. |
| 281 | +- A send event can fail if the user isn’t a group member or the client doesn’t support targeted messages. |
| 282 | + |
| 283 | + > [!NOTE] |
| 284 | + > Teams' backward compatibility ensures older clients don't show targeted messages if unsupported. |
| 285 | +
|
| 286 | +Ensure to handle these errors appropriately in your agent or bot. |
| 287 | + |
| 288 | +# [Teams SDK](#tab/tsdk) |
| 289 | + |
| 290 | +The following table lists error codes, error descriptions, and developer actions for Teams SDK: |
| 291 | + |
| 292 | +| Status code | Error code | Description | Developer action | |
| 293 | +| --- | --- | --- | --- | --- | |
| 294 | +| 400 | `Bad argument` | Missing recipient when creating targeted message. | Ensure `WithRecipient`(account, `isTargeted`: `true`) is called with valid Account object. | |
| 295 | +| 400 | `Bad argument` | Recipient passed on update or delete. | Don't pass recipient on update or delete. | |
| 296 | +| 403 | `BotNotInConversationRoster` | Bot isn't a member of the conversation. | Ensure bot is installed in the conversation before sending targeted messages. | |
| 297 | +| 404 | `ActivityNotFoundInConversation` | The message ID provided couldn't be found in the conversation. The message is unavailable as it was deleted or auto removed after 24 hours. | Ensure the agent either sends a new targeted message or waits for user input, as per business logic. | |
| 298 | + |
| 299 | +# [HTTP](#tab/api) |
| 300 | + |
| 301 | +The following table lists error codes, error descriptions, and developer actions for REST APIs: |
| 302 | + |
| 303 | +| Status code | Error code | Description | Developer action | |
| 304 | +| --- | --- | --- | --- | --- | |
| 305 | +| 400 | `Bad argument` | Recipient is missing in the `Send TM` API. | Ensure that recipient is included when the agent sends the message as it's mandatory. | |
| 306 | +| 400 | `Bad argument` | Recipient is included in the payload of the `Edit TM` API | Ensure the recipient isn't included in the payload of the `Edit TM` API. | |
| 307 | +| 403 | `BotNotInConversationRoster` | Bot isn't a member of the conversation. | Ensure bot is installed in the conversation before sending targeted messages. | |
| 308 | +| 404 | `ActivityNotFoundInConversation` | The message ID provided couldn't be found in the conversation. The message is unavailable as it was deleted or auto removed after 24 hours. | Ensure the agent either sends a new targeted message or waits for user input, as per business logic. | |
| 309 | + |
| 310 | +--- |
| 311 | +> [!TIP] |
| 312 | +> It's recommended that if sending a targeted message fails, consider a fallback mechanism such as sending a 1:1 chat message. |
| 313 | +
|
| 314 | +You’ll find more details on the other error codes for sending messages [here](../bots/build-conversational-capability.md#status-codes-from-bot-conversational-apis). |
| 315 | + |
| 316 | +## See also |
| 317 | + |
| 318 | +- [Proactive messages](../bots/how-to/conversations/send-proactive-messages.md) |
| 319 | +- [Send and receive messages](../bots/build-conversational-capability.md) |
0 commit comments