Proactive Messaging
In Sending Messages, you were shown how to respond to an event when it happens. However, there are times when you want to send a message to the user without them sending a message first. This is called proactive messaging. You can do this by using the send method in the app instance. This approach is useful for sending notifications or reminders to the user.
The main thing to note is that you need to have the conversationId of the chat or channel that you want to send the message to. It's a good idea to store this value somewhere from an activity handler so that you can use it for proactive messaging later.
import { MessageActivity } from '@microsoft/teams.api';
import { App } from '@microsoft/teams.apps';
// ...
// This would be some persistent storage
const myConversationIdStorage = new Map<string, string>();
// Installation is just one place to get the conversation id. All activities
// have the conversation id, so you can use any activity to get it.
app.on('install.add', async ({ activity, send }) => {
// Save the conversation id in
myConversationIdStorage.set(activity.from.aadObjectId!, activity.conversation.id);
await send('Hi! I am going to remind you to say something to me soon!');
notificationQueue.addReminder(activity.from.aadObjectId!, sendProactiveNotification, 10_000);
});
Then, when you want to send a proactive message, you can retrieve the conversationId from storage and use it to send the message.
import { MessageActivity } from '@microsoft/teams.api';
import { App } from '@microsoft/teams.apps';
// ...
const sendProactiveNotification = async (userId: string) => {
const conversationId = myConversationIdStorage.get(userId);
if (!conversationId) {
return;
}
const activity = new MessageActivity('Hey! It\'s been a while. How are you?');
await app.send(conversationId, activity);
};
In this example, you see how to get the conversationId using one of the activity handlers. This is a good place to store the conversation id, but you can also do this in other places like when the user installs the app or when they sign in. The important thing is that you have the conversation id stored somewhere so you can use it later.
Targeted Proactive Messages​
Targeted messages are coming soon in May 2026.
Targeted messages, also known as ephemeral messages, are delivered to a specific user in a shared conversation. From a single user's perspective, they appear as regular inline messages in a conversation. Other participants won't see these messages.
When sending targeted messages proactively, you must explicitly specify the recipient account.
import { MessageActivity, Account } from '@microsoft/teams.api';
// When sending proactively, you must provide an explicit recipient account
const sendTargetedNotification = async (conversationId: string, recipient: Account) => {
await app.send(
conversationId,
new MessageActivity('This is a private notification just for you!')
.withRecipient(recipient, true)
);
};
Proactive Threading​
Threads are only rendered visibly in Teams channels. In 1:1 chats, group chats, and meetings, messages appear flat; passing a thread root message ID has no visible effect in those scopes.
To proactively send a message as a reply to a thread, use app.reply() with the conversation ID and thread root message ID. The SDK constructs the threaded conversation ID for you.
// Send to a specific thread proactively
await app.reply(conversationId, messageId, 'Thread update!');
// Send to a flat conversation (1:1, group chat)
await app.reply(conversationId, 'Hello!');
You can also pass just a conversation ID to app.reply() for non-threaded conversations such as 1:1 chats and group chats. To target a specific thread, include the thread root message ID as shown above.
For reactive threading (within a handler), see Threading.
Thread ID Helper​
For advanced scenarios, the toThreadedConversationId() helper constructs the threaded conversation ID directly. Use it with app.send() when you need full control.
import { toThreadedConversationId } from '@microsoft/teams.apps';
const threadId = toThreadedConversationId(conversationId, messageId);
await app.send(threadId, 'Sent via helper');