Description
I'm working on a Microsoft Teams bot (based on the Bot Framework) that, when I send a message (e.g. an adaptive card) to a channel, should return a message identifier (reply.id) - referred to in my code as messageResponse. I then pass this identifier to an external API that I use for search (search task) in my application - so the user can navigate to specific posts (tasks) in the Teams feed.
What am I trying to accomplish?
Sending messages to the channel:
I use the turnContext.sendActivity method inside adapter.continueConversationAsync to send a message to a specific channel. In a local environment (e.g. emulator, local server), the method returns an object containing an id property (e.g. { id: "1234567890", ... }), which I treat as messageResponse.
Forward messageResponse to the frontend:
Once the message is sent, the response (containing reply.id) goes to the React application. I then pass this id (placed in the object I send as messageResponse) to the external API. I use this API in the "search task" Tab, where I retrieve an array of posts (tasks) from the feed, allowing the user to navigate to a specific post on channel.
Problem:
In the local environment, everything works correctly - the sendActivity method returns an object with an id property. However, when deployed to the development environment (Azure), the response does not contain reply.id (that is, messageResponse is empty or does not exist). As a result:
I cannot pass the id to the external API. The search module (search task) does not have access to the full array of posts with the correct message id, making it impossible to redirect the user to a specific post in the feed.
Code snippets: Server (Typescript rest - Bot) - sending messages proactively:
server.post(
'/api/sendProactiveTextMessage',
restify.plugins.queryParser(),
restify.plugins.bodyParser(), // Add more parsers if needed
async (req, res) => {
const pageSize = 100
let continuationToken: string | undefined = undefined
const messageResponses = []
const channelId = req.body.teamsData.channelId
const groupId = req.body.teamsData.groupId
if (!groupId || !channelId) {
res.status(400)
return res.json({
success: false,
error: 'Brak groupId lub channelId',
})
}
do {
const pagedData = await notificationApp.notification.getPagedInstallations(pageSize, continuationToken)
const installations = pagedData.data
continuationToken = pagedData.continuationToken
const now = new Date()
for (const target of installations) {
if (target.type === 'Channel') {
cardData = AdaptiveCards.declare<CardData>(notificationTemplate).render({
// <--- private data!! --->
})
try {
const conversationReference = target.conversationReference
let messageId: string | undefined
await adapter.continueConversationAsync(
config.botId,
conversationReference,
async (turnContext: TurnContext) => {
const replyActivity = MessageFactory.attachment(CardFactory.adaptiveCard(cardData))
const reply = await turnContext.sendActivity(replyActivity)
messageId = reply?.id
}
)
res.json({
success: true,
text: messageId,
})
} catch (error) {
console.error('Błąd:', error)
messageResponses.push({
success: false,
error: error.message,
})
}
}
}
} while (continuationToken)
res.json({
success: true,
messageResponses: messageResponses,
})
}
)
Fragments React (getting to /api/sendProactiveTextMessage):
const response = await fetch(`https://${process.env.REACT_APP_BOT_DOMAIN}/api/sendProactiveTextMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(flaskDataWithTeams),
redirect: 'follow',
});
const data = await response.json();
console.log('API answer:', data);
if (!data.messageResponses || data.messageResponses.length === 0) {
throw new Error('The API response does not contain messageResponses.');
}
// messageResponses is later used to search and redirect to posts
Summary:
-
Purpose: To get the message identifier (reply.id, or messageResponse) when a message is sent to a channel, in order to pass it to an external API. I use this API to query the full array of posts (tasks) and enable navigation to a specific post in the Teams channel.
-
Problem: In the development/production environment (Azure) turnContext.sendActivity does not return reply.id for messages sent to the channel, even though locally it works fine.
-
Question: does anyone know the reason for this behavior? Is this a known limitation for channel messages? What approach do you recommend to get the id of the message in the production environment to pass to the downstream API?
I would appreciate any tips or suggestions on this problem. Thank you for your help!
Activity