Sending a direct message to a user in Microsoft Teams

In this guide, we'll cover how to update a multi-tenant Microsoft Teams bot to send direct messages to Teams users using Knock. It assumes that you have already created a Microsoft Teams channel in Knock as outlined in the Microsoft Teams integration overview guide.

Here's what we'll cover in this guide:

  • Modeling a multi-tenant application in Knock using Tenants
  • Adding required scopes to your Microsoft Teams app's manifest
  • Setting required Tenant and User channel data when a Microsoft Teams bot is installed in a user's personal scope
  • Triggering a workflow with a user recipient to send a direct message to a Teams user

Prerequisites

Make sure your bot has been registered with Microsoft Bot Framework and is deployed to Azure. Knock does not manage deploying and configuring your bot. To set up Knock to send notifications as your bot, see How to connect to Teams with Knock.

Key concepts

There are two key concepts you'll see throughout the following docs that are foundational to how Knock's Microsoft Teams integration works: tenants and objects.

About tenants

Tenants in Knock are meant to represent groups of users who typically share the same resources. You might call these "accounts," "organizations," "workspaces," or something similar. In a typical Microsoft Teams implementation, you'll store the ID of a Microsoft Entra tenant on a corresponding tenant in Knock.

If you already use Knock's tenant concept to power other 'account-based' features, you likely create tenants in Knock when an account or organization is created in your application.

💡
Note: Our best-practice recommendation is that tenants in Knock should map one-to-one to whatever abstraction you use to model accounts, organizations, or workspaces. You can think of tenants as the top-level container within your data model that you use to power multi-tenancy in your application.

Merging channel data

In this implementation, we'll actually store the required channel data for an MsTeamsConnection across two different entities in Knock: a Tenant and an User. This is because we want to store the ms_teams_tenant_id for the Microsoft Entra tenant on the Knock Tenant and the ms_teams_user_id for the Microsoft Teams user on the Knock User.

When you trigger a workflow using this recipient and tenant, Knock will merge the channel data from the Tenant and the User to send the message to the correct Microsoft Teams user.

Adding required scopes to your app's manifest

In order for your bot to send direct messages to users in Microsoft Teams, you'll need to update your Microsoft Teams app's manifest so that it includes the personal scope for your bot.

In your manifest.json file, add personal to your bot's array of scopes:

Setting Tenant and User channel data

Your application should provide a method for admin users to set up your bot within a Microsoft Teams tenant. When this occurs, your backend should update the channel data associated with the Knock Tenant, passing in the tenant ID of the Microsoft Teams tenant.

If you're using Knock's Node SDK, your code might look like this:

Here, KNOCK_MS_TEAMS_CHANNEL_ID is the channel ID of your Microsoft Teams integration within Knock, and "knocklabs" is the ID of the current Tenant logged into the application.

Once your Microsoft Teams bot is installed in a user's personal scope, your bot's messaging endpoint will receive an installation update event. You can use this event to update the channel data associated with the Knock User.

If you're using the Bot Framework SDK for JavaScript with the Knock Node SDK, your code will look something like this:

Here, "user_1n38knd" represents the ID of the Knock User associated with this Microsoft Teams user, and should be replaced with a Knock User ID that you retrieve from your database. How you get this ID depends upon your specific application.

Triggering a workflow

Once you have saved the user's Microsoft Teams user ID as channel data, you can trigger a workflow to send a message to that user's DM channel. Here's an example of how to trigger a workflow using the Knock Node SDK: