-
Notifications
You must be signed in to change notification settings - Fork 199
How to configure Message Extension capability within your Teams app
Message Extension allows users to interact with your web service while composing messages in the Microsoft Teams client. Users can invoke your web service to assist message composition, from the message compose box, or from the search bar.
Message Extensions are implemented on top of the Bot support architecture within Teams. Learn more from Build message extensions for Teams .
To configure message extension as additional capability, please make sure:
- You have a Teams application and its manifest.
- You have a Microsoft 365 account to test the application.
For adding message extension to a tab Teams app, please go to: Add message extension to a tab Teams app.
For adding message extension to a bot Teams app, please go to: Add message extension to a bot Teams app.
Following are the steps to add Message Extension capability to a tab app:
- Create a message extension Teams app using Teams Toolkit.
- Update manifest file.
- Bring message extension code to your project.
- Setup local debug environment.
- Move the application to Azure.
Please check the guide Create a message extension app with Teams Toolkit
-
You can configure message extension in
appPackage/manifest.json
. You can also refer to message extension schema if you want to customize.Example:
"composeExtensions": [ { "botId": "${{BOT_ID}}", "commands": [ { "id": "createCard", "context": [ "compose" ], "description": "Command to run action to create a Card from Compose Box", "title": "Create Card", "type": "action", "parameters": [ { "name": "title", "title": "Card title", "description": "Title for the card", "inputType": "text" }, { "name": "subTitle", "title": "Subtitle", "description": "Subtitle for the card", "inputType": "text" }, { "name": "text", "title": "Text", "description": "Text for the card", "inputType": "textarea" } ] }, { "id": "shareMessage", "context": [ "message" ], "description": "Test command to run action on message context (message sharing)", "title": "Share Message", "type": "action", "parameters": [ { "name": "includeImage", "title": "Include Image", "description": "Include image in Hero Card", "inputType": "toggle" } ] }, { "id": "searchQuery", "context": [ "compose", "commandBox" ], "description": "Test command to run query", "title": "Search", "type": "query", "parameters": [ { "name": "searchQuery", "title": "Search Query", "description": "Your search query", "inputType": "text" } ] } ], "messageHandlers": [ { "type": "link", "value": { "domains": [ "*.botframework.com" ] } } ] } ]
-
Add your bot domain to the
validDomains
field. Example:"validDomains": [ "${{BOT_DOMAIN}}" ],
BOT_ID
andBOT_DOMAIN
are built-in variables of Teams Toolkit. They will be replaced with the true value in runtime based on your current environment(local, dev, etc.).
- Bring your own message extension app code into your project. If you don't have one, you can use the message extension app project previously created and copy the source code to into your current project. We suggest you to copy them into a
bot/
folder. Your folder structure will be like:We suggest you to re-organize the folder structure and create a root package.json as:|-- .vscode/ |-- appPackage/ |-- env/ |-- infra/ |-- public/ |-- bot/ <!--message extension source code--> | |-- index.ts | |-- config.ts | |-- teamsBot.ts | |-- package.json | |-- tsconfig.json | |-- web.config | |-- .webappignore |-- src/ <!--your current source code--> | |-- index.tsx |-- package.json |-- tsconfig.json |-- teamsapp.local.yml |-- teamsapp.yml
|-- .vscode/ |-- appPackage/ |-- env/ |-- infra/ |-- bot/ <!--message extension source code--> | |-- index.ts | |-- config.ts | |-- teamsBot.ts | |-- package.json | |-- tsconfig.json | |-- web.config | |-- .webappignore |-- tab/ <!--move your current source code to a new sub folder--> | |-- public/ | |-- src/ | | |-- index.tsx | |-- package.json | |-- tsconfig.json |-- package.json <!--root package.json--> |-- teamsapp.local.yml |-- teamsapp.yml
- Add following to your root package.json:
Notice: If you are working on a javascript project, the bot doesn't need build. Please remove "build:bot" script and change "build" script to "npm run build:tab".
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "install:bot": "cd bot && npm install", "install:tab": "cd tab && npm install", "install": "concurrently \"npm run install:bot\" \"npm run install:tab\"", "dev:bot": "cd bot && npm run dev", "start:tab": "cd tab && npm run start", "build:tab": "cd tab && npm run build", "build:bot": "cd bot && npm run build", "build": "concurrently \"npm run build:tab\" \"npm run build:bot\"" }, "devDependencies": { "@microsoft/teamsfx-run-utils": "alpha" }, "dependencies": { "concurrently": "^7.6.0" },
-
Modify
.vscode/launch.json
. Add aAttach to Bot
configuration and config it under other configurations and compounds. You can also find thisAttach to Bot
configuration in previously created message extension project."configurations":[ ... + { + "name": "Attach to Bot", + "type": "pwa-node", + "request": "attach", + "port": 9239, + "restart": true, + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen" + }, { "name": "Attach to Frontend (Edge)", "type": "pwa-msedge", "request": "launch", "url": "https://teams.microsoft.com/l/app/${local:teamsAppId}?installAppPackage=true&webjoin=true&${account-hint}", "presentation": { "group": "all", "hidden": true }, + "cascadeTerminateToConfigurations": [ + "Attach to Bot" + ], "internalConsoleOptions": "neverOpen" }, { "name": "Attach to Frontend (Chrome)", "type": "pwa-chrome", "request": "launch", "url": "https://teams.microsoft.com/l/app/${local:teamsAppId}?installAppPackage=true&webjoin=true&${account-hint}", "presentation": { "group": "all", "hidden": true }, + "cascadeTerminateToConfigurations": [ + "Attach to Bot" + ], "internalConsoleOptions": "neverOpen" }, ], "compounds": [ { "name": "Debug (Edge)", "configurations": [ "Attach to Frontend (Edge)", + "Attach to Bot" ], "preLaunchTask": "Start Teams App Locally", "presentation": { "group": "all", "order": 1 }, "stopAll": true }, { "name": "Debug (Chrome)", "configurations": [ "Attach to Frontend (Chrome)", + "Attach to Bot" ], "preLaunchTask": "Start Teams App Locally", "presentation": { "group": "all", "order": 2 }, "stopAll": true } ]
-
Modify
.vscode/task.json
. Add 2 new tasks:Start local tunnel
andStart bot
. AddStart bot
to taskStart application
'sdependOn
. ConfigStart bot
andStart frondend
'scwd
option since we already move tab and bot's code totab/
andbot/
folder separately."tasks":[ { + "label": "Start local tunnel", + "type": "teamsfx", + "command": "debug-start-local-tunnel", + "args": { + "ngrokArgs": "http 3978 --log=stdout --log-format=logfmt", + "env": "local", + "output": { + // output to .env.local + "endpoint": "BOT_ENDPOINT", // output tunnel endpoint as BOT_ENDPOINT + "domain": "BOT_DOMAIN" // output tunnel domain as BOT_DOMAIN + } + }, + "isBackground": true, + "problemMatcher": "$teamsfx-local-tunnel-watch" + }, + { + "label": "Start bot", + "type": "shell", + "command": "npm run dev:teamsfx", + "isBackground": true, + "options": { + "cwd": "${workspaceFolder}/bot" + }, + "problemMatcher": { + "pattern": [ + { + "regexp": "^.*$", + "file": 0, + "location": 1, + "message": 2 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "[nodemon] starting", + "endsPattern": "restify listening to|Bot/ME service listening at|[nodemon] app crashed" + } + } + }, { "label": "Start frontend", "type": "shell", "command": "npm run dev:teamsfx", "isBackground": true, "options": { + "cwd": "${workspaceFolder}/tab" }, "problemMatcher": { "pattern": { "regexp": "^.*$", "file": 0, "location": 1, "message": 2 }, "background": { "activeOnStart": true, "beginsPattern": ".*", "endsPattern": "Compiled|Failed|compiled|failed" } } }, { "label": "Start application", "dependsOn": [ "Start frontend", + "Start bot" ] }, ]
-
Manually merge
teamsapp.local.yml
file with yours. Then updatefile/createOrUpdateEnvironmentFile
action under deploy:deploy: - uses: file/createOrUpdateEnvironmentFile # Generate runtime environment variables with: target: ./tab/.localSettings envs: BROWSER: none HTTPS: true PORT: 53000 SSL_CRT_FILE: ${{SSL_CRT_FILE}} SSL_KEY_FILE: ${{SSL_KEY_FILE}} - uses: file/createOrUpdateEnvironmentFile # Generate runtime environment variables with: target: ./bot/.localSettings envs: BOT_ID: ${{BOT_ID}} BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
Here is an sample project for reference.
-
Open the
Run and Debug Activity Panel
and selectDebug (Edge)
orDebug (Chrome)
. Press F5 to preview your Teams app locally.
- Manually merge the content in
infra/
andteamsapp.yml
folder with yours. UpdateazureStorage/deploy
andazureAppService/zipDeploy
'sartifactFolder
to target totab/
andbot/
folder respectively.# Deploy bits to Azure Storage Static Website - uses: azureStorage/deploy with: workingDirectory: . # Deploy base folder artifactFolder: ./tab/build # The resource id of the cloud resource to be deployed to. This key will be generated by arm/deploy action automatically. You can replace it with your existing Azure Resource id or add it to your environment variable file. resourceId: ${{TAB_AZURE_STORAGE_RESOURCE_ID}} # Deploy your application to Azure App Service using the zip deploy feature. # For additional details, please refer to https://aka.ms/zip-deploy-to-app-services. - uses: azureAppService/zipDeploy with: # Deploy base folder artifactFolder: ./bot # Can be changed to any ignore file location, leave blank will ignore nothing ignoreFile: ./bot/.webappignore # The resource id of the cloud resource to be deployed to. This key will be generated by arm/deploy action automatically. You can replace it with your existing Azure Resource id or add it to your environment variable file. resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
Here is an sample project for reference.
-
Run
Teams: Provision in the cloud
command in Visual Studio Code to apply the bicep to Azure. -
Run
Teams: Deploy to cloud
command in Visual Studio Code to deploy your app code to Azure. -
Open the
Run and Debug Activity Panel
and selectLaunch Remote (Edge)
orLaunch Remote (Chrome)
. Press F5 to preview your Teams app.
Since message extensions are implemented on top of the Bot support architecture within Teams, adding Message Extension to a bot Teams app is simpler than adding to a tab Teams app.
Following are the steps to add Message Extension capability to a bot app:
- Create a message extension Teams app using Teams Toolkit.
- Update manifest file.
- Bring message extension code to your project.
Please check the guide Create a message extension app with Teams Toolkit
-
You can configure message extension in
appPackage/manifest.json
. You can also refer to message extension schema if you want to customize.Example:
"composeExtensions": [ { "botId": "${{BOT_ID}}", "commands": [ { "id": "createCard", "context": [ "compose" ], "description": "Command to run action to create a Card from Compose Box", "title": "Create Card", "type": "action", "parameters": [ { "name": "title", "title": "Card title", "description": "Title for the card", "inputType": "text" }, { "name": "subTitle", "title": "Subtitle", "description": "Subtitle for the card", "inputType": "text" }, { "name": "text", "title": "Text", "description": "Text for the card", "inputType": "textarea" } ] }, { "id": "shareMessage", "context": [ "message" ], "description": "Test command to run action on message context (message sharing)", "title": "Share Message", "type": "action", "parameters": [ { "name": "includeImage", "title": "Include Image", "description": "Include image in Hero Card", "inputType": "toggle" } ] }, { "id": "searchQuery", "context": [ "compose", "commandBox" ], "description": "Test command to run query", "title": "Search", "type": "query", "parameters": [ { "name": "searchQuery", "title": "Search Query", "description": "Your search query", "inputType": "text" } ] } ], "messageHandlers": [ { "type": "link", "value": { "domains": [ "*.botframework.com" ] } } ] } ]
-
Add your bot domain to the
validDomains
field. Example:"validDomains": [ "${{BOT_DOMAIN}}" ],
BOT_ID
andBOT_DOMAIN
are built-in variables of Teams Toolkit. They will be replaced with the true value in runtime based on your current environment(local, dev, etc.).
-
If you are adding message extension to a bot Teams app, then you should already have a class that extends
TeamsActivityHandler
. Bring your own message extension functions, or copy functions from your previously created message extension app to your own class. Below is an example if you copy functions from Teams Toolkit created message extension app:public class YourHandler extends TeamsActivityHandler{ /** * your own code */ //message extension code // Action. public async handleTeamsMessagingExtensionSubmitAction( context: TurnContext, action: any ): Promise<any> {} // Search. public async handleTeamsMessagingExtensionQuery(context: TurnContext, query: any): Promise<any> {} public async handleTeamsMessagingExtensionSelectItem( context: TurnContext, obj: any ): Promise<any> {} // Link Unfurling. public async handleTeamsAppBasedLinkQuery(context: TurnContext, query: any): Promise<any> {} } async function createCardCommand(context: TurnContext, action: MessagingExtensionAction): Promise<MessagingExtensionResponse> { } async function shareMessageCommand(context: TurnContext, action: MessagingExtensionAction): Promise<MessagingExtensionResponse> { }
There are other commonly suggested next steps, for example:
Build Custom Engine Copilots
- Build a basic AI chatbot for Teams
- Build an AI agent chatbot for Teams
- Expand AI bot's knowledge with your content
Scenario-based Tutorials
- Send notifications to Teams
- Respond to chat commands in Teams
- Respond to card actions in Teams
- Embed a dashboard canvas in Teams
Extend your app across Microsoft 365
- Teams tabs in Microsoft 365 and Outlook
- Teams message extension for Outlook
- Add Outlook Add-in to a Teams app
App settings and Microsoft Entra Apps
- Manage Application settings with Teams Toolkit
- Manage Microsoft Entra Application Registration with Teams Toolkit
- Use an existing Microsoft Entra app
- Use a multi-tenant Microsoft Entra app
Configure multiple capabilities
- How to configure Tab capability within your Teams app
- How to configure Bot capability within your Teams app
- How to configure Message Extension capability within your Teams app
Add Authentication to your app
- How to add single sign on in Teams Toolkit for Visual Studio Code
- How to enable Single Sign-on in Teams Toolkit for Visual Studio
Connect to cloud resources
- How to integrate Azure Functions with your Teams app
- How to integrate Azure API Management
- Integrate with Azure SQL Database
- Integrate with Azure Key Vault
Deploy apps to production