Home > Software engineering >  Sending proactive messages from an outside process to organizational users via Teams chat bot
Sending proactive messages from an outside process to organizational users via Teams chat bot

Time:03-23

I have an Azure Bot installed in my organization through Teams. Interactions with the bot are properly functioning.

We have a scenario where we need to send notifications to our users from an external process (C# app running in Azure).

I attempted to use the Bot Framework REST API to create a conversation with a user in order to then message them with the notification as outlined here

This scenario does not work as I cannot get an access token for a bot that is not using the global Bot Framework Tenant. Our Bot is installed on our Azure tenant as a SingleTenant BotType so I get the following error:

 Application with identifier 'BOT-APP-ID' was not found in the directory 'Bot Framework'

I've poured over various options including DirectLine channels, BotConnector SDK and Power Automate - but nothing seems to fit with my needs.

Is there a way to use a Rest API against the Bot we have installed to create conversations and send messages? This would be ideal as then I can initiate these notifications directly from the events that triggered them.

UPDATE

Hilton's answer below brought some much needed clarity to the situation. Ultimately I had to deploy a new Bot set to use the Multitenant BotType.

This configured an AppRegistration tied to the Bot set to use MultiTenant as well.

Additionally in the WebApp where you have your api/messages endpoint hosted you have to include a property called MicrosoftAppType and set that to MultiTenant as well. Here is the full configuration required for the WebApp:

MicrosoftAppId: [The AppId of the AppRegistration]
MicrosoftAppPassword: [The Secret of the AppRegistration]
MicrosoftAppTenantId: [Your Tenant Id]
MicrosoftAppType: MultiTenant

To capture the ConversationId, ServiceUrl and UserId I added the following to the OnMembersAddedAsync

foreach (var member in membersAdded)
{
    if (!string.IsNullOrEmpty(member.AadObjectId))
    {
        //This is a user in our AAD. Store the conversation id reference:
        var userId = member.AadObjectId;
        var serviceUrl = turnContext.Activity.ServiceUrl;
        var conversationId = turnContext.Activity.Conversation.Id;

        //Save variables to your state store here...
    }
    else
    {
         // This is likely a test outside of Teams 
         //var userId = member.Id; //<-- Not used in my scenario
    }
}

Then in my external app (A Console in this example) I can use those variables (along with the AppRegistration credentials) to create a Bot ConnectorClient and update the conversation:

using Microsoft.Bot.Connector;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;


var botAppId = "[BOT_ID/APP_REG_ID]";
var botAppKey = "[APP_REG_SECRET]";
var conversationId = "[CONVERSATION_ID]";
var serviceUrl = "[SERVICE_URL]";

MicrosoftAppCredentials.TrustServiceUrl(serviceUrl);
var connector = new Microsoft.Bot.Connector.ConnectorClient(new Uri(serviceUrl), botAppId, botAppKey);

var activity = new Activity()
{
    Text = "Proactively saying **Hello**",
    Type = ActivityTypes.Message,
    Conversation = new ConversationAccount(false, "personal", conversationId)
};

try
{
    var result = await connector.Conversations.SendToConversationAsync(conversationId, activity);

    Console.WriteLine("Notification sent!");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

CodePudding user response:

Proactive messaging is definitely what you're looking for, but there are a few important things to be aware of. Here is a sample https://github.com/pnp/teams-dev-samples/tree/main/samples/bot-proactive-messaging that will hopefully be useful - I included both a C# and a Node version as well as some links to further reading, and here is a link to a video session where I talk more about the concept: https://www.youtube.com/watch?v=mM7-fYdcJhw&t=1398s.

In simple terms, remember that Bot Framework can be used in many contexts, Teams is just one of those. Importantly, unlike other contexts, when you're in Teams there is no concept of "creating" a conversation with the user. There is only ever a single "conversation", and you are basically "continuing" the conversation. As a result, you want to call continueConversation. In the same sample I linked above, here is the relevant line. Under the covers, this is indeed calling a REST API, but wrapped like this it's easier.

As the sample shows, however, because you can't start a conversation, and can only continue one, you need to make sure you have the conversation context already, and that may also mean ensuring that the user has the bot installed already into the personal context (which is what actually does start the conversation). Here is where that happens in the sample.

If your users have the bot installed already, then its just a case of storing the conversation context like I show in the sample. If not, and you want to learn how you can pre-install the bot, see this question: Proactively Install / Push Apps in Teams for Multiple Users

  • Related