Contents
Test out Aptible AI for your team
So, you're exploring ways to utilize Teams to enable more productivity and efficiency for your organization? If you're reading this, you're likely either:
Just beginning to investigate the effort involved in building a Teams bot using the Python SDK; or
You’ve been trying to build a bot in Teams, and you’re looking for examples that illustrate how you might build something more production-ready.
Either way, this guide will get you sorted out.
What we’re going to build: a bot-based Teams app
Before we get moving, let’s make sure you’re on the right train. In parts 1 and 2 of this tutorial, we’re going to walk through (and provide code samples for) how to:
Create a new bot application in Teams and install it into our organization while we develop it.
Use the Microsoft Bot Framework to build an “echo” bot that just echoes back the message it receives. We’ll start here so that we can establish a feedback loop and iterate quickly.
Extend our echo bot with asynchronous processing capabilities. This will allow us to process messages using a background worker (like Celery) for expensive operations, like calling an LLM or slow external APIs.
Use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Understand Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understand the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.
For part 1, however, we'll stop after step 3 to give everyone a (much needed) little break 😮💨
Step 0: Get organized
The first and most important thing we need to do is to get organized. The Microsoft APIs and SDKs can be deep and daunting (and at times, disorienting) so it’s important that we start by setting ourselves up for success.
Prerequisites
First, let’s start with a checklist of things you’ll need to have if you want to follow along with the tutorial:
An Azure account (or a colleague with an Azure account) with enough access to create and manage an App Registration in Microsoft Entra ID.
A Python environment with Python 3.12 or later (it may work with older versions of Python, but we haven’t tried it).
Access to a Microsoft Teams account for testing and bot configuration.
The ability to side-load apps into your Teams organization.
The ability to use
ngrok
ordevtunnel
(or a similar tool) so that your bot can receive messages from Teams as you’re building.
Useful bookmarks
You’ll also want to have the following URLs bookmarked, since you’ll be using them a lot:
The Microsoft Teams Developer Portal (https://dev.teams.microsoft.com/)
The App Management page of the Teams Admin Panel (https://admin.teams.microsoft.com/policies/manage-apps)
We’ll add some more specific bookmarks as we scaffold out our app in the next section.
Step 1: Scaffold the app
The first thing we need to do is scaffold our app so that we can quickly get into a feedback loop. We’ll start by setting up a very basic Flask application, starting an ngrok
tunnel, and then setting up the Microsoft entities necessary to get Teams to start sending direct messages to our bot through that tunnel.
Scaffold a simple Flask app
We’ll start by standing up a very simple “hello world” Flask app. So that we can point our ngrok
tunnel at it.
Create and activate a new virtualenv
for the project, and install Flask
We’re using Python’s built-in venv
module for simplicity, but you can feel free to use your favorite dependency manager (uv
, poetry
, pipenv
, etc) if you like.
# Create a directory for the project $ mkdir teams-bot $ cd teams-bot # Create a new virtual environment in a .venv folder in our project $ python -m venv .venv # Activate the virtual environment $ . .venv/bin/activate # Install Flask $ pip
Create a “hello world” app
Now that we’ve got a virtual environment ready to go, we can create a simple Flask app just to serve up the text “hello world”. Create a new file called app.py
with the following contents:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
Start the app and make it listen on all hosts
Back in your terminal, start the app:
$ flask --app=app run --host=0.0.0.0 --port=5001 * Serving Flask app 'app' * Debug mode: off WARNING: This is a development server. Do not use it in
⚠️ You can use whatever port you like here, but note that Flask’s default of 5000 is typically already in use by MacOS’ *AirDrop & Handoff* feature, so we’re using 5001
Make sure the app is working
Open up a browser and head to http://127.0.0.1:5001/. You should see a page like this:
Open a tunnel
With your app listening, open up a new terminal in a separate tab or window, and start an ngrok
tunnel pointing to the Flask app:
You should see something like this:
Make sure the tunnel is working
With the tunnel open, navigate to the URL it assigned to you on the “Forwarding” line (ending in ngrok-free.app
. You’ll get a page like this one:
Be sure to click the Visit Site button to make sure that the tunnel is opened. Once you click it, you should see your app again.
You only have to click the “Visit Site” link once for each tunnel opened, so as long as you leave the tunnel running, you won’t have to click it again.
Just remember that if you do close your tunnel and open a new one, you’ll need to click through before Teams will be able to send you messages!
Step 2. Bot configuration
Before we can start writing the bot-specific code (we'll provide code samples for this later), we need to scaffold a few administrative things in order to create a package that we can install (or rather, “side-load”) in a Teams organization.
From the Teams Developer Portal, click Create a new app and give it whatever name you like, then click Add.
Navigate to Configure → App features, and click Bot.
Click the Create a new bot link below the “Select an existing bot” dropdown.
Click New bot, and give your bot a name (I typically use the same name as the app), and click Add.
Note that this may take a moment, as it will create a new “app registration” in the Azure portal behind the scenes.
Click on the bot you created.
Navigate to Configure in the sidebar, and set the Endpoint address to (your ngrok tunnel URL)/events (e.g.,
https://9999-111-22-333-444.ngrok-free.app/events
). Note that we haven’t created this endpoint yet, but we’ll do that in the next section.You may also find it helpful to to bookmark this page so that you can update the URL in the future.
Navigate to Client secrets in the sidebar, and click Add a client secret for your bot.
Copy the generated secret and keep it somewhere safe, like a password manager, then click OK.
Navigate back to the Bots list (you can use the button at the top of the page).
Copy the Bot ID for your bot.
Navigate back to Apps → (your app) → Configure → Basic Information, and fill in all of the required fields (using the Bot ID you copied for the Application (client) ID field), then click Save.
Note that you can use fake information (e.g., example.com URLs) for things you don’t have yet. They just need to have valid values for now.
Navigate to Configure → App features, and click Bot.
In the Select an existing bot dropdown, select the bot you created.
Under the Select the scopes where people can use your bot, check the Personal and Team checkboxes.
Next, navigate to Configure → Permissions → Team Permissions → Application, check the box for
ChannelMessage.Send.Group
, to make sure our bot can reply to the messages it receives.Scroll to the bottom and click Save.
Boom! Bot configuration complete ✅
Review
You should now have:
An app with all of the basic information filled in.
A bot with its endpoint address configured to send messages to our
ngrok
tunnel.A client ID (the Bot ID) and secret that we’ll use to authenticate our app.
Step 3. Publish the Teams app
Before we can install our bot into our organization, we need to:
Publish it to the organization.
Make sure our organization supports installing “custom apps”.
Approve our app for installation.
Let’s get started.
Publish the app to the organization
From the Teams App Developer Portal, navigate to Apps → (your app) → Publish → Publish to org.
Click Publish.
Enable custom app installation for your organization
In a new browser tab, navigate to the Microsoft Teams Admin Center, and then to Teams apps → Manage apps in the sidebar.
Click the Actions dropdown in the upper right, and then click Org-wide app settings.
Make sure the Custom apps toggle is “on”.
Click Save, then use the sidebar to navigate to Teams apps → Permission policies.
Click Global (Org-wide default).
Ensure that the Custom apps dropdown is set to Allow all apps.
These settings will allow you to install “custom” (i.e., unpublished) apps like the one we’re building.
Approve the app for installation
Finally, we need to approve our custom app that we published to our organization, so that we can request to install it.
Navigate to Teams apps → Manage apps.
Search for the name of your app in the table’s search field.
Your app probably says it’s “blocked”, which is what we’re going to fix.
Click on the name of your app.
Click Publish, and confirm the action in the modal that appears.
Install the app
Finally, we can install our app into our team!
From the Teams App Developer Portal, navigate to Apps → (your app).
Click the Preview In Teams button in the upper right of the page.
Teams will open to an installation page for your bot.
Click Add to a team.
Select the team to which you want to add your bot, and then click Set up a bot.
Congrats, you’ve installed your app in Teams! 🎉
Make sure messages are making it to our app
While we haven’t set up the webhook endpoint (/events
) yet, we can still try to send our bot a message and see if a request shows up in our logs.
Create a new Teams post in the channel where you installed your bot, and make sure to tag your bot in it.
You should see some 404s in the ngrok and Flask logs in your terminal, letting us know that Teams tried to POST a message to our /events
webhook (albeit unsuccessfully):
Review
We’ve now configured our organization to:
Allow the installation of “custom” (unpublished) apps in our organization.
Approved our app for installation within our organization while we develop it.
Installed our app into a team.
Checked that messages are making from Teams to our Flask app through our tunnel.
Next up: let’s write some code!
So, you're exploring ways to utilize Teams to enable more productivity and efficiency for your organization? If you're reading this, you're likely either:
Just beginning to investigate the effort involved in building a Teams bot using the Python SDK; or
You’ve been trying to build a bot in Teams, and you’re looking for examples that illustrate how you might build something more production-ready.
Either way, this guide will get you sorted out.
What we’re going to build: a bot-based Teams app
Before we get moving, let’s make sure you’re on the right train. In parts 1 and 2 of this tutorial, we’re going to walk through (and provide code samples for) how to:
Create a new bot application in Teams and install it into our organization while we develop it.
Use the Microsoft Bot Framework to build an “echo” bot that just echoes back the message it receives. We’ll start here so that we can establish a feedback loop and iterate quickly.
Extend our echo bot with asynchronous processing capabilities. This will allow us to process messages using a background worker (like Celery) for expensive operations, like calling an LLM or slow external APIs.
Use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Understand Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understand the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.
For part 1, however, we'll stop after step 3 to give everyone a (much needed) little break 😮💨
Step 0: Get organized
The first and most important thing we need to do is to get organized. The Microsoft APIs and SDKs can be deep and daunting (and at times, disorienting) so it’s important that we start by setting ourselves up for success.
Prerequisites
First, let’s start with a checklist of things you’ll need to have if you want to follow along with the tutorial:
An Azure account (or a colleague with an Azure account) with enough access to create and manage an App Registration in Microsoft Entra ID.
A Python environment with Python 3.12 or later (it may work with older versions of Python, but we haven’t tried it).
Access to a Microsoft Teams account for testing and bot configuration.
The ability to side-load apps into your Teams organization.
The ability to use
ngrok
ordevtunnel
(or a similar tool) so that your bot can receive messages from Teams as you’re building.
Useful bookmarks
You’ll also want to have the following URLs bookmarked, since you’ll be using them a lot:
The Microsoft Teams Developer Portal (https://dev.teams.microsoft.com/)
The App Management page of the Teams Admin Panel (https://admin.teams.microsoft.com/policies/manage-apps)
We’ll add some more specific bookmarks as we scaffold out our app in the next section.
Step 1: Scaffold the app
The first thing we need to do is scaffold our app so that we can quickly get into a feedback loop. We’ll start by setting up a very basic Flask application, starting an ngrok
tunnel, and then setting up the Microsoft entities necessary to get Teams to start sending direct messages to our bot through that tunnel.
Scaffold a simple Flask app
We’ll start by standing up a very simple “hello world” Flask app. So that we can point our ngrok
tunnel at it.
Create and activate a new virtualenv
for the project, and install Flask
We’re using Python’s built-in venv
module for simplicity, but you can feel free to use your favorite dependency manager (uv
, poetry
, pipenv
, etc) if you like.
# Create a directory for the project $ mkdir teams-bot $ cd teams-bot # Create a new virtual environment in a .venv folder in our project $ python -m venv .venv # Activate the virtual environment $ . .venv/bin/activate # Install Flask $ pip
Create a “hello world” app
Now that we’ve got a virtual environment ready to go, we can create a simple Flask app just to serve up the text “hello world”. Create a new file called app.py
with the following contents:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
Start the app and make it listen on all hosts
Back in your terminal, start the app:
$ flask --app=app run --host=0.0.0.0 --port=5001 * Serving Flask app 'app' * Debug mode: off WARNING: This is a development server. Do not use it in
⚠️ You can use whatever port you like here, but note that Flask’s default of 5000 is typically already in use by MacOS’ *AirDrop & Handoff* feature, so we’re using 5001
Make sure the app is working
Open up a browser and head to http://127.0.0.1:5001/. You should see a page like this:
Open a tunnel
With your app listening, open up a new terminal in a separate tab or window, and start an ngrok
tunnel pointing to the Flask app:
You should see something like this:
Make sure the tunnel is working
With the tunnel open, navigate to the URL it assigned to you on the “Forwarding” line (ending in ngrok-free.app
. You’ll get a page like this one:
Be sure to click the Visit Site button to make sure that the tunnel is opened. Once you click it, you should see your app again.
You only have to click the “Visit Site” link once for each tunnel opened, so as long as you leave the tunnel running, you won’t have to click it again.
Just remember that if you do close your tunnel and open a new one, you’ll need to click through before Teams will be able to send you messages!
Step 2. Bot configuration
Before we can start writing the bot-specific code (we'll provide code samples for this later), we need to scaffold a few administrative things in order to create a package that we can install (or rather, “side-load”) in a Teams organization.
From the Teams Developer Portal, click Create a new app and give it whatever name you like, then click Add.
Navigate to Configure → App features, and click Bot.
Click the Create a new bot link below the “Select an existing bot” dropdown.
Click New bot, and give your bot a name (I typically use the same name as the app), and click Add.
Note that this may take a moment, as it will create a new “app registration” in the Azure portal behind the scenes.
Click on the bot you created.
Navigate to Configure in the sidebar, and set the Endpoint address to (your ngrok tunnel URL)/events (e.g.,
https://9999-111-22-333-444.ngrok-free.app/events
). Note that we haven’t created this endpoint yet, but we’ll do that in the next section.You may also find it helpful to to bookmark this page so that you can update the URL in the future.
Navigate to Client secrets in the sidebar, and click Add a client secret for your bot.
Copy the generated secret and keep it somewhere safe, like a password manager, then click OK.
Navigate back to the Bots list (you can use the button at the top of the page).
Copy the Bot ID for your bot.
Navigate back to Apps → (your app) → Configure → Basic Information, and fill in all of the required fields (using the Bot ID you copied for the Application (client) ID field), then click Save.
Note that you can use fake information (e.g., example.com URLs) for things you don’t have yet. They just need to have valid values for now.
Navigate to Configure → App features, and click Bot.
In the Select an existing bot dropdown, select the bot you created.
Under the Select the scopes where people can use your bot, check the Personal and Team checkboxes.
Next, navigate to Configure → Permissions → Team Permissions → Application, check the box for
ChannelMessage.Send.Group
, to make sure our bot can reply to the messages it receives.Scroll to the bottom and click Save.
Boom! Bot configuration complete ✅
Review
You should now have:
An app with all of the basic information filled in.
A bot with its endpoint address configured to send messages to our
ngrok
tunnel.A client ID (the Bot ID) and secret that we’ll use to authenticate our app.
Step 3. Publish the Teams app
Before we can install our bot into our organization, we need to:
Publish it to the organization.
Make sure our organization supports installing “custom apps”.
Approve our app for installation.
Let’s get started.
Publish the app to the organization
From the Teams App Developer Portal, navigate to Apps → (your app) → Publish → Publish to org.
Click Publish.
Enable custom app installation for your organization
In a new browser tab, navigate to the Microsoft Teams Admin Center, and then to Teams apps → Manage apps in the sidebar.
Click the Actions dropdown in the upper right, and then click Org-wide app settings.
Make sure the Custom apps toggle is “on”.
Click Save, then use the sidebar to navigate to Teams apps → Permission policies.
Click Global (Org-wide default).
Ensure that the Custom apps dropdown is set to Allow all apps.
These settings will allow you to install “custom” (i.e., unpublished) apps like the one we’re building.
Approve the app for installation
Finally, we need to approve our custom app that we published to our organization, so that we can request to install it.
Navigate to Teams apps → Manage apps.
Search for the name of your app in the table’s search field.
Your app probably says it’s “blocked”, which is what we’re going to fix.
Click on the name of your app.
Click Publish, and confirm the action in the modal that appears.
Install the app
Finally, we can install our app into our team!
From the Teams App Developer Portal, navigate to Apps → (your app).
Click the Preview In Teams button in the upper right of the page.
Teams will open to an installation page for your bot.
Click Add to a team.
Select the team to which you want to add your bot, and then click Set up a bot.
Congrats, you’ve installed your app in Teams! 🎉
Make sure messages are making it to our app
While we haven’t set up the webhook endpoint (/events
) yet, we can still try to send our bot a message and see if a request shows up in our logs.
Create a new Teams post in the channel where you installed your bot, and make sure to tag your bot in it.
You should see some 404s in the ngrok and Flask logs in your terminal, letting us know that Teams tried to POST a message to our /events
webhook (albeit unsuccessfully):
Review
We’ve now configured our organization to:
Allow the installation of “custom” (unpublished) apps in our organization.
Approved our app for installation within our organization while we develop it.
Installed our app into a team.
Checked that messages are making from Teams to our Flask app through our tunnel.
Next up: let’s write some code!
So, you're exploring ways to utilize Teams to enable more productivity and efficiency for your organization? If you're reading this, you're likely either:
Just beginning to investigate the effort involved in building a Teams bot using the Python SDK; or
You’ve been trying to build a bot in Teams, and you’re looking for examples that illustrate how you might build something more production-ready.
Either way, this guide will get you sorted out.
What we’re going to build: a bot-based Teams app
Before we get moving, let’s make sure you’re on the right train. In parts 1 and 2 of this tutorial, we’re going to walk through (and provide code samples for) how to:
Create a new bot application in Teams and install it into our organization while we develop it.
Use the Microsoft Bot Framework to build an “echo” bot that just echoes back the message it receives. We’ll start here so that we can establish a feedback loop and iterate quickly.
Extend our echo bot with asynchronous processing capabilities. This will allow us to process messages using a background worker (like Celery) for expensive operations, like calling an LLM or slow external APIs.
Use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Understand Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understand the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.
For part 1, however, we'll stop after step 3 to give everyone a (much needed) little break 😮💨
Step 0: Get organized
The first and most important thing we need to do is to get organized. The Microsoft APIs and SDKs can be deep and daunting (and at times, disorienting) so it’s important that we start by setting ourselves up for success.
Prerequisites
First, let’s start with a checklist of things you’ll need to have if you want to follow along with the tutorial:
An Azure account (or a colleague with an Azure account) with enough access to create and manage an App Registration in Microsoft Entra ID.
A Python environment with Python 3.12 or later (it may work with older versions of Python, but we haven’t tried it).
Access to a Microsoft Teams account for testing and bot configuration.
The ability to side-load apps into your Teams organization.
The ability to use
ngrok
ordevtunnel
(or a similar tool) so that your bot can receive messages from Teams as you’re building.
Useful bookmarks
You’ll also want to have the following URLs bookmarked, since you’ll be using them a lot:
The Microsoft Teams Developer Portal (https://dev.teams.microsoft.com/)
The App Management page of the Teams Admin Panel (https://admin.teams.microsoft.com/policies/manage-apps)
We’ll add some more specific bookmarks as we scaffold out our app in the next section.
Step 1: Scaffold the app
The first thing we need to do is scaffold our app so that we can quickly get into a feedback loop. We’ll start by setting up a very basic Flask application, starting an ngrok
tunnel, and then setting up the Microsoft entities necessary to get Teams to start sending direct messages to our bot through that tunnel.
Scaffold a simple Flask app
We’ll start by standing up a very simple “hello world” Flask app. So that we can point our ngrok
tunnel at it.
Create and activate a new virtualenv
for the project, and install Flask
We’re using Python’s built-in venv
module for simplicity, but you can feel free to use your favorite dependency manager (uv
, poetry
, pipenv
, etc) if you like.
# Create a directory for the project $ mkdir teams-bot $ cd teams-bot # Create a new virtual environment in a .venv folder in our project $ python -m venv .venv # Activate the virtual environment $ . .venv/bin/activate # Install Flask $ pip
Create a “hello world” app
Now that we’ve got a virtual environment ready to go, we can create a simple Flask app just to serve up the text “hello world”. Create a new file called app.py
with the following contents:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
Start the app and make it listen on all hosts
Back in your terminal, start the app:
$ flask --app=app run --host=0.0.0.0 --port=5001 * Serving Flask app 'app' * Debug mode: off WARNING: This is a development server. Do not use it in
⚠️ You can use whatever port you like here, but note that Flask’s default of 5000 is typically already in use by MacOS’ *AirDrop & Handoff* feature, so we’re using 5001
Make sure the app is working
Open up a browser and head to http://127.0.0.1:5001/. You should see a page like this:
Open a tunnel
With your app listening, open up a new terminal in a separate tab or window, and start an ngrok
tunnel pointing to the Flask app:
You should see something like this:
Make sure the tunnel is working
With the tunnel open, navigate to the URL it assigned to you on the “Forwarding” line (ending in ngrok-free.app
. You’ll get a page like this one:
Be sure to click the Visit Site button to make sure that the tunnel is opened. Once you click it, you should see your app again.
You only have to click the “Visit Site” link once for each tunnel opened, so as long as you leave the tunnel running, you won’t have to click it again.
Just remember that if you do close your tunnel and open a new one, you’ll need to click through before Teams will be able to send you messages!
Step 2. Bot configuration
Before we can start writing the bot-specific code (we'll provide code samples for this later), we need to scaffold a few administrative things in order to create a package that we can install (or rather, “side-load”) in a Teams organization.
From the Teams Developer Portal, click Create a new app and give it whatever name you like, then click Add.
Navigate to Configure → App features, and click Bot.
Click the Create a new bot link below the “Select an existing bot” dropdown.
Click New bot, and give your bot a name (I typically use the same name as the app), and click Add.
Note that this may take a moment, as it will create a new “app registration” in the Azure portal behind the scenes.
Click on the bot you created.
Navigate to Configure in the sidebar, and set the Endpoint address to (your ngrok tunnel URL)/events (e.g.,
https://9999-111-22-333-444.ngrok-free.app/events
). Note that we haven’t created this endpoint yet, but we’ll do that in the next section.You may also find it helpful to to bookmark this page so that you can update the URL in the future.
Navigate to Client secrets in the sidebar, and click Add a client secret for your bot.
Copy the generated secret and keep it somewhere safe, like a password manager, then click OK.
Navigate back to the Bots list (you can use the button at the top of the page).
Copy the Bot ID for your bot.
Navigate back to Apps → (your app) → Configure → Basic Information, and fill in all of the required fields (using the Bot ID you copied for the Application (client) ID field), then click Save.
Note that you can use fake information (e.g., example.com URLs) for things you don’t have yet. They just need to have valid values for now.
Navigate to Configure → App features, and click Bot.
In the Select an existing bot dropdown, select the bot you created.
Under the Select the scopes where people can use your bot, check the Personal and Team checkboxes.
Next, navigate to Configure → Permissions → Team Permissions → Application, check the box for
ChannelMessage.Send.Group
, to make sure our bot can reply to the messages it receives.Scroll to the bottom and click Save.
Boom! Bot configuration complete ✅
Review
You should now have:
An app with all of the basic information filled in.
A bot with its endpoint address configured to send messages to our
ngrok
tunnel.A client ID (the Bot ID) and secret that we’ll use to authenticate our app.
Step 3. Publish the Teams app
Before we can install our bot into our organization, we need to:
Publish it to the organization.
Make sure our organization supports installing “custom apps”.
Approve our app for installation.
Let’s get started.
Publish the app to the organization
From the Teams App Developer Portal, navigate to Apps → (your app) → Publish → Publish to org.
Click Publish.
Enable custom app installation for your organization
In a new browser tab, navigate to the Microsoft Teams Admin Center, and then to Teams apps → Manage apps in the sidebar.
Click the Actions dropdown in the upper right, and then click Org-wide app settings.
Make sure the Custom apps toggle is “on”.
Click Save, then use the sidebar to navigate to Teams apps → Permission policies.
Click Global (Org-wide default).
Ensure that the Custom apps dropdown is set to Allow all apps.
These settings will allow you to install “custom” (i.e., unpublished) apps like the one we’re building.
Approve the app for installation
Finally, we need to approve our custom app that we published to our organization, so that we can request to install it.
Navigate to Teams apps → Manage apps.
Search for the name of your app in the table’s search field.
Your app probably says it’s “blocked”, which is what we’re going to fix.
Click on the name of your app.
Click Publish, and confirm the action in the modal that appears.
Install the app
Finally, we can install our app into our team!
From the Teams App Developer Portal, navigate to Apps → (your app).
Click the Preview In Teams button in the upper right of the page.
Teams will open to an installation page for your bot.
Click Add to a team.
Select the team to which you want to add your bot, and then click Set up a bot.
Congrats, you’ve installed your app in Teams! 🎉
Make sure messages are making it to our app
While we haven’t set up the webhook endpoint (/events
) yet, we can still try to send our bot a message and see if a request shows up in our logs.
Create a new Teams post in the channel where you installed your bot, and make sure to tag your bot in it.
You should see some 404s in the ngrok and Flask logs in your terminal, letting us know that Teams tried to POST a message to our /events
webhook (albeit unsuccessfully):
Review
We’ve now configured our organization to:
Allow the installation of “custom” (unpublished) apps in our organization.
Approved our app for installation within our organization while we develop it.
Installed our app into a team.
Checked that messages are making from Teams to our Flask app through our tunnel.
Next up: let’s write some code!
Test out Aptible AI for your team
Step 4. Build the bot
Now that we’ve got messages flowing, we can start building out our bot. We’ll start by building a simple “echo bot” that simply echoes back whatever message it receives.
Echo bot
Let’s update our app.py
to implement an echo bot.
Install some new packages
First, we need a few more packages:
botbuilder-core
, which is Microsoft’s Bot Framework SDK for Python.flask[async]
andaiohttp
, sincebotbuilder-core
uses async Python features for the most part, and so we’ll want to update our Flask app to behave asynchronously as well.
In your virtualenv, go ahead and install these packages:
$ pip install aiohttp botbuilder-core 'flask[async]'
Update the Flask app
Next, we’ll want to update our Flask app with the following code. Read the comments
import json import os from azure.core.exceptions import DeserializationError from botbuilder.core import ( BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext, ) from botbuilder.core.teams import TeamsActivityHandler from botbuilder.schema import Activity, ActivityTypes from flask import Flask, jsonify, request # Create a Flask app, which can also store our config. app = Flask(__name__) # Extract environment variables that we'll need to authenticate our bot. try: app.config.update( TEAMS_BOT_CLIENT_ID=os.environ["TEAMS_BOT_CLIENT_ID"], TEAMS_BOT_CLIENT_SECRET=os.environ["TEAMS_BOT_CLIENT_SECRET"], ) except KeyError: raise LookupError( "Environment variables TEAMS_BOT_CLIENT_ID and TEAMS_BOT_CLIENT_SECRET " "must be set." ) # Create a "handler" that implements various callbacks for events that Teams sends us. class BotHandler(TeamsActivityHandler): """ Determines what to do for incoming events with per-category methods. https://learn.microsoft.com/en-us/microsoftteams/platform/bots/bot-basics?tabs=python """ async def on_message_activity(self, turn_context: TurnContext) -> None: """Handle “message activity” events.""" return await turn_context.send_activity( Activity( type=ActivityTypes.message, text_format="markdown", text=f"**Received:** {turn_context.activity.text}", ) ) bot = BotHandler() # Create an adapter that will handle authentication and routing of messages to the bot. bot_adapter = BotFrameworkAdapter( BotFrameworkAdapterSettings( # Replace these with settings from environment variables in a real app. # None values allow requests from the Bot Framework Emulator. app_id=app.config["TEAMS_BOT_CLIENT_ID"], app_password=app.config["TEAMS_BOT_CLIENT_SECRET"], ) ) # Add a route to handle Teams messages. @app.route("/events", methods=["POST"]) async def handle_event(): """Respond to an event from Microsoft Teams.""" try: payload = request.json except json.JSONDecodeError: print(request) return jsonify({"error": "Bad request"}), 400 # React to the activity try: activity = Activity.deserialize(payload) except DeserializationError: return jsonify({"error": "Bad request"}), 400 auth_header = request.headers.get("authorization", "") try: invoke_response = await bot_adapter.process_activity( activity, auth_header, bot.on_turn, ) # Note: more more except blocks may be needed, per: # https://github.com/microsoft/botbuilder-python/blob/main/libraries/botbuilder-core/botbuilder/core/integration/aiohttp_channel_service_exception_middleware.py#L19 except TypeError: return jsonify({"error": "Bad request"}), 400 else: if invoke_response: return jsonify(invoke_response.body), invoke_response.status else: return jsonify({}), 204
Try it out
Let’s try it out!
If you still have your Flask app running from before, stop it with CTRL+C.
Export your bot’s client ID and secret so your app can get them from the environment.
$ export TEAMS_BOT_CLIENT_ID=your-client-id-here $ export TEAMS_BOT_CLIENT_SECRET
Re-run your app, this time specifying
--reload
so that we don’t have to remember to restart it every time.$ flask --app=app run --host=0.0.0.0 --port=5001 --reload
Tag your bot in a Teams post (or in a reply to an existing post)
Coming soon...
In part 2 (coming in a few weeks), we'll dive into the next 3 steps that we mentioned at the beginning of this tutorial:
How to use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Learning Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understanding the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.
To get notified when Part 2 comes out, you can subscribe using the form below.
Step 4. Build the bot
Now that we’ve got messages flowing, we can start building out our bot. We’ll start by building a simple “echo bot” that simply echoes back whatever message it receives.
Echo bot
Let’s update our app.py
to implement an echo bot.
Install some new packages
First, we need a few more packages:
botbuilder-core
, which is Microsoft’s Bot Framework SDK for Python.flask[async]
andaiohttp
, sincebotbuilder-core
uses async Python features for the most part, and so we’ll want to update our Flask app to behave asynchronously as well.
In your virtualenv, go ahead and install these packages:
$ pip install aiohttp botbuilder-core 'flask[async]'
Update the Flask app
Next, we’ll want to update our Flask app with the following code. Read the comments
import json import os from azure.core.exceptions import DeserializationError from botbuilder.core import ( BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext, ) from botbuilder.core.teams import TeamsActivityHandler from botbuilder.schema import Activity, ActivityTypes from flask import Flask, jsonify, request # Create a Flask app, which can also store our config. app = Flask(__name__) # Extract environment variables that we'll need to authenticate our bot. try: app.config.update( TEAMS_BOT_CLIENT_ID=os.environ["TEAMS_BOT_CLIENT_ID"], TEAMS_BOT_CLIENT_SECRET=os.environ["TEAMS_BOT_CLIENT_SECRET"], ) except KeyError: raise LookupError( "Environment variables TEAMS_BOT_CLIENT_ID and TEAMS_BOT_CLIENT_SECRET " "must be set." ) # Create a "handler" that implements various callbacks for events that Teams sends us. class BotHandler(TeamsActivityHandler): """ Determines what to do for incoming events with per-category methods. https://learn.microsoft.com/en-us/microsoftteams/platform/bots/bot-basics?tabs=python """ async def on_message_activity(self, turn_context: TurnContext) -> None: """Handle “message activity” events.""" return await turn_context.send_activity( Activity( type=ActivityTypes.message, text_format="markdown", text=f"**Received:** {turn_context.activity.text}", ) ) bot = BotHandler() # Create an adapter that will handle authentication and routing of messages to the bot. bot_adapter = BotFrameworkAdapter( BotFrameworkAdapterSettings( # Replace these with settings from environment variables in a real app. # None values allow requests from the Bot Framework Emulator. app_id=app.config["TEAMS_BOT_CLIENT_ID"], app_password=app.config["TEAMS_BOT_CLIENT_SECRET"], ) ) # Add a route to handle Teams messages. @app.route("/events", methods=["POST"]) async def handle_event(): """Respond to an event from Microsoft Teams.""" try: payload = request.json except json.JSONDecodeError: print(request) return jsonify({"error": "Bad request"}), 400 # React to the activity try: activity = Activity.deserialize(payload) except DeserializationError: return jsonify({"error": "Bad request"}), 400 auth_header = request.headers.get("authorization", "") try: invoke_response = await bot_adapter.process_activity( activity, auth_header, bot.on_turn, ) # Note: more more except blocks may be needed, per: # https://github.com/microsoft/botbuilder-python/blob/main/libraries/botbuilder-core/botbuilder/core/integration/aiohttp_channel_service_exception_middleware.py#L19 except TypeError: return jsonify({"error": "Bad request"}), 400 else: if invoke_response: return jsonify(invoke_response.body), invoke_response.status else: return jsonify({}), 204
Try it out
Let’s try it out!
If you still have your Flask app running from before, stop it with CTRL+C.
Export your bot’s client ID and secret so your app can get them from the environment.
$ export TEAMS_BOT_CLIENT_ID=your-client-id-here $ export TEAMS_BOT_CLIENT_SECRET
Re-run your app, this time specifying
--reload
so that we don’t have to remember to restart it every time.$ flask --app=app run --host=0.0.0.0 --port=5001 --reload
Tag your bot in a Teams post (or in a reply to an existing post)
Coming soon...
In part 2 (coming in a few weeks), we'll dive into the next 3 steps that we mentioned at the beginning of this tutorial:
How to use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Learning Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understanding the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.
To get notified when Part 2 comes out, you can subscribe using the form below.
Step 4. Build the bot
Now that we’ve got messages flowing, we can start building out our bot. We’ll start by building a simple “echo bot” that simply echoes back whatever message it receives.
Echo bot
Let’s update our app.py
to implement an echo bot.
Install some new packages
First, we need a few more packages:
botbuilder-core
, which is Microsoft’s Bot Framework SDK for Python.flask[async]
andaiohttp
, sincebotbuilder-core
uses async Python features for the most part, and so we’ll want to update our Flask app to behave asynchronously as well.
In your virtualenv, go ahead and install these packages:
$ pip install aiohttp botbuilder-core 'flask[async]'
Update the Flask app
Next, we’ll want to update our Flask app with the following code. Read the comments
import json import os from azure.core.exceptions import DeserializationError from botbuilder.core import ( BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext, ) from botbuilder.core.teams import TeamsActivityHandler from botbuilder.schema import Activity, ActivityTypes from flask import Flask, jsonify, request # Create a Flask app, which can also store our config. app = Flask(__name__) # Extract environment variables that we'll need to authenticate our bot. try: app.config.update( TEAMS_BOT_CLIENT_ID=os.environ["TEAMS_BOT_CLIENT_ID"], TEAMS_BOT_CLIENT_SECRET=os.environ["TEAMS_BOT_CLIENT_SECRET"], ) except KeyError: raise LookupError( "Environment variables TEAMS_BOT_CLIENT_ID and TEAMS_BOT_CLIENT_SECRET " "must be set." ) # Create a "handler" that implements various callbacks for events that Teams sends us. class BotHandler(TeamsActivityHandler): """ Determines what to do for incoming events with per-category methods. https://learn.microsoft.com/en-us/microsoftteams/platform/bots/bot-basics?tabs=python """ async def on_message_activity(self, turn_context: TurnContext) -> None: """Handle “message activity” events.""" return await turn_context.send_activity( Activity( type=ActivityTypes.message, text_format="markdown", text=f"**Received:** {turn_context.activity.text}", ) ) bot = BotHandler() # Create an adapter that will handle authentication and routing of messages to the bot. bot_adapter = BotFrameworkAdapter( BotFrameworkAdapterSettings( # Replace these with settings from environment variables in a real app. # None values allow requests from the Bot Framework Emulator. app_id=app.config["TEAMS_BOT_CLIENT_ID"], app_password=app.config["TEAMS_BOT_CLIENT_SECRET"], ) ) # Add a route to handle Teams messages. @app.route("/events", methods=["POST"]) async def handle_event(): """Respond to an event from Microsoft Teams.""" try: payload = request.json except json.JSONDecodeError: print(request) return jsonify({"error": "Bad request"}), 400 # React to the activity try: activity = Activity.deserialize(payload) except DeserializationError: return jsonify({"error": "Bad request"}), 400 auth_header = request.headers.get("authorization", "") try: invoke_response = await bot_adapter.process_activity( activity, auth_header, bot.on_turn, ) # Note: more more except blocks may be needed, per: # https://github.com/microsoft/botbuilder-python/blob/main/libraries/botbuilder-core/botbuilder/core/integration/aiohttp_channel_service_exception_middleware.py#L19 except TypeError: return jsonify({"error": "Bad request"}), 400 else: if invoke_response: return jsonify(invoke_response.body), invoke_response.status else: return jsonify({}), 204
Try it out
Let’s try it out!
If you still have your Flask app running from before, stop it with CTRL+C.
Export your bot’s client ID and secret so your app can get them from the environment.
$ export TEAMS_BOT_CLIENT_ID=your-client-id-here $ export TEAMS_BOT_CLIENT_SECRET
Re-run your app, this time specifying
--reload
so that we don’t have to remember to restart it every time.$ flask --app=app run --host=0.0.0.0 --port=5001 --reload
Tag your bot in a Teams post (or in a reply to an existing post)
Coming soon...
In part 2 (coming in a few weeks), we'll dive into the next 3 steps that we mentioned at the beginning of this tutorial:
How to use OpenAI to give our bot application some brains so that it can help with more complex tasks.
Learning Microsoft Graph and how it relates to the Microsoft Bot Framework (we'll use this to retrieve the conversation history for a Teams post to pass along to our bot so it can follow the conversation).
Understanding the different kinds of events that a Teams bot can handle and implement one to send a welcome message when the bot gets installed for the first time.