2
votes

I'm working on a Teams bot that needs the ability to start a new 1:1 conversation with a known user (i.e., we know the Teams user ID).

I've looked at the "complete-csharp" OfficeDev samples on GitHub (https://github.com/OfficeDev/microsoft-teams-sample-complete-csharp) as well as the Teams-related parts of the Graph API but I don't see any affordance for starting a new conversation.

Our goal is to have our bot ping a known user on a schedule by inviting them into a 1:1 chat and requesting their feedback. A button in the bot's message will reveal the feedback form (via task module).

1
Yes! Thank you so much for the thorough and detailed answer.Easy Rhino

1 Answers

4
votes

Update

Bot Framework has added in code specific for Teams that makes a lot of the code in this answer moot or incorrect. See this sample for sending proactive messages in Teams, now.

Teams calls that a "Proactive Message". So long as you get the user ID that Teams uses, it's fairly easy to do.

Per the docs, Proactive messaging for bots:

Bots can create new conversations with an individual Microsoft Teams user as long as your bot has user information obtained through previous addition in a personal, groupChat or team scope. This information enables your bot to proactively notify them. For instance, if your bot was added to a team, it could query the team roster and send users individual messages in personal chats, or a user could @mention another user to trigger the bot to send that user a direct message.

The easiest way to do this is through the Microsoft.Bot.Builder.Teams middleware.

Note: The Microsoft.Bot.Builder.Teams extension is still in Prerelease for V4, which is why samples and code are kind of hard to find for it.

Adding the Middleware

In Startup.cs:

var credentials = new SimpleCredentialProvider(Configuration["MicrosoftAppId"], Configuration["MicrosoftAppPassword"]);

services.AddSingleton(credentials);

[...]

services.AddBot<YourBot>(options =>
{
    options.CredentialProvider = credentials;

    options.Middleware.Add(
        new TeamsMiddleware(
            new ConfigurationCredentialProvider(this.Configuration)));
[...]

Prepping Your Bot

In your main <YourBot>.cs:

private readonly SimpleCredentialProvider _credentialProvider;

[...]

public <YourBot>(ConversationState conversationState, SimpleCredentialProvider CredentialProvider)
{
     _credentialProvider = CredentialProvider;

[...]

Sending the Message

var teamConversationData = turnContext.Activity.GetChannelData<TeamsChannelData>();
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), _credentialProvider.AppId, _credentialProvider.Password);

var userId = <UserIdToSendTo>;
var tenantId = teamConversationData.Tenant.Id;
var parameters = new ConversationParameters
{
    Members = new[] { new ChannelAccount(userId) },
    ChannelData = new TeamsChannelData
    {
        Tenant = new TenantInfo(tenantId),
    },
};

var conversationResource = await connectorClient.Conversations.CreateConversationAsync(parameters);
var message = Activity.CreateMessageActivity();
message.Text = "This is a proactive message.";
await connectorClient.Conversations.SendToConversationAsync(conversationResource.Id, (Activity)message);

Note: If you need to get user ID's, you can use:

var members = (await turnContext.TurnState.Get<IConnectorClient>().Conversations.GetConversationMembersAsync(
    turnContext.Activity.GetChannelData<TeamsChannelData>().Team.Id).ConfigureAwait(false)).ToList();

Also, I didn't need this in my testing, but if you get 401 errors, you may need to trust the Teams ServiceUrl:

MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl); 

Resources