Sending Messages
Sending messages is a core part of an agent's functionality. With all activity handlers, a send method is provided which allows your handlers to send a message back to the user to the relevant conversation.
app.on('message', async ({ activity, send }) => {
await send(`You said: ${activity.text}`);
});
In the above example, the handler gets a message activity, and uses the send method to send a reply to the user.
app.on('signin.verify-state', async ({ send }) => {
await send('You have successfully signed in!');
});
You are not restricted to only replying to message activities. In the above example, the handler is listening to signin.verify-state events, which are sent when a user successfully signs in.
This shows an example of sending a text message. Additionally, you are able to send back things like adaptive cards by using the same send method. Look at the adaptive card section for more details.
Streaming​
You may also stream messages to the user which can be useful for long messages, or AI generated messages. The SDK makes this simple for you by providing a stream function which you can use to send messages in chunks.
app.on('message', async ({ activity, stream }) => {
stream.emit('hello');
stream.emit(', ');
stream.emit('world!');
// result message: "hello, world!"
});
Streaming is currently only supported in 1:1 conversations, not group chats or channels

@Mention​
Sending a message at @mentions a user is as simple including the details of the user using the addMention method
app.on('message', async ({ send, activity }) => {
await send(new MessageActivity('hi!').addMention(activity.from));
});
Targeted 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, making them useful for authentication flows, help or error responses, personal reminders, or sharing contextual information without cluttering the group conversation.
To send a targeted message when responding to an incoming activity, use the withRecipient method with the recipient account and set the targeting flag to true.
import { MessageActivity } from '@microsoft/teams.api';
app.on('message', async ({ send, activity }) => {
// Using withRecipient with isTargeted=true explicitly targets the specified recipient
await send(
new MessageActivity('This message is only visible to you!')
.withRecipient(activity.from, true)
);
});
Reactions​
Reactions allow your agent to add or remove emoji reactions on messages in a conversation, and to receive reactions added by users. See the Message Reactions guide for full coverage.
Threading​
In Teams channels, messages can be organized into threads. The SDK provides helpers to simplify working with threads.
Reactive Threading (Within a Handler)​
When your agent receives a message in a thread, the conversation context already carries the thread ID. Use send() to send a message in the same thread without quoting, or reply() to send with a visual quote of the inbound message.
app.on('message', async ({ send, reply }) => {
// Send in the same thread, no quote
await send('Acknowledged');
// Send in the same thread with a visual quote of the inbound message
await reply('Got it!');
});
For proactive threading (sending to a thread outside of a handler), see Proactive Messaging.
Quoted Replies​
Quoted replies are coming soon in May 2026.
Quoted replies let your agent reference a previous message in the conversation. When a user sends a message that quotes another message, your agent receives structured metadata about the quoted content. Your agent can also send messages that quote previous messages.
Receiving Quoted Replies​
When a user quotes a message and sends it to your agent, the quoted reply metadata is available on the inbound activity. Use the getQuotedMessages() method to access all quoted reply entities.
app.on('message', async ({ activity, reply }) => {
const quotes = activity.getQuotedMessages();
if (quotes.length > 0) {
const quote = quotes[0].quotedReply;
await reply(
`You quoted message ${quote.messageId} from ${quote.senderName}: "${quote.preview}"`
);
}
});
Each quoted reply entity contains the quoted message's ID, sender information, a preview of the quoted text, and whether the quoted message has been deleted.
Sending a Quoted Reply​
When your agent calls reply(), the SDK automatically stamps a quoted reply entity referencing the inbound message. The reply will appear as a quoted reply in Teams.
app.on('message', async ({ reply }) => {
// reply() automatically quotes the inbound message
await reply('Got it!');
});
To quote a different message in the same conversation (not the inbound message), use the quote() method with the message ID you want to quote.
app.on('message', async ({ quote }) => {
// Quote a specific message by its ID
const parentMessageId = '1772050244572';
await quote(parentMessageId, 'Referencing an earlier message');
});
Building Quoted Replies for Proactive Send​
For proactive scenarios (using app.send()) or when quoting multiple messages, use the addQuote() method on a message activity. Pass the message ID and an optional response text.
import { MessageActivity } from '@microsoft/teams.api';
const parentMessageId = '1772050244572';
const firstMessageId = '1772050244573';
const secondMessageId = '1772050244574';
// Single quote with response below it
let msg = new MessageActivity()
.addQuote(parentMessageId, 'Here is my response');
await app.send(conversationId, msg);
// Multiple quotes with interleaved responses
msg = new MessageActivity()
.addQuote(firstMessageId, 'response to first')
.addQuote(secondMessageId, 'response to second');
await app.send(conversationId, msg);
// Grouped quotes — omit response to group quotes together
msg = new MessageActivity('see below for previous messages')
.addQuote(firstMessageId)
.addQuote(secondMessageId, 'response to both');
await app.send(conversationId, msg);