Updates from: 02/04/2021 04:12:50
Service Microsoft Docs article Related commit history on GitHub Change details
platform https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4 https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/bots/how-to/bots-filesv4.md
@@ -121,7 +121,7 @@ The following table describes the content properties of the attachment:
#### Invoke activity when the user accepts the file
-An invoke activity is sent to the bot if and when the user accepts the file. It contains the OneDrive for Business placeholder URL that the bot can then issue a `PUT` into to transfer the file contents. For information on uploading to the OneDrive URL, see [Upload bytes to the upload session](/onedrive/developer/rest-api/api/driveitem_createuploadsession#upload-bytes-to-the-upload-session).
+An invoke activity is sent to the bot if and when the user accepts the file. It contains the OneDrive for Business placeholder URL that the bot can then issue a `PUT` to transfer the file contents. For information on uploading to the OneDrive URL, see [upload bytes to the upload session](/onedrive/developer/rest-api/api/driveitem_createuploadsession#upload-bytes-to-the-upload-session).
The following example shows a concise version of the invoke activity that the bot receives:
@@ -184,6 +184,47 @@ The following table describes the content properties of the attachment:
| `uniqueId` | OneDrive or SharePoint drive item ID. | | `fileType` | Type of file, such as .pdf or .docx. |
+### Fetching inline images from message
+
+Fetch inline images that are part of the message using the Bot's access token.
+
+![Inline image](../../assets/images/bots/inline-image.png)
+
+```csharp
+private async Task ProcessInlineImage(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
+{ΓÇïΓÇïΓÇïΓÇïΓÇï
+ var attachment = turnContext.Activity.Attachments[0];
+ var client = _clientFactory.CreateClient();
+ // Get Bot's access token to fetch inline image.
+ var token = await new MicrosoftAppCredentials(microsoftAppId, microsoftAppPassword).GetTokenAsync();
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
+ var responseMessage = await client.GetAsync(attachment.ContentUrl);
+ // Save the inline image to Files directory.
+ var filePath = Path.Combine("Files", "ImageFromUser.png");
+ using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
+ {ΓÇïΓÇïΓÇïΓÇïΓÇï
+ await responseMessage.Content.CopyToAsync(fileStream);
+ }ΓÇïΓÇïΓÇïΓÇïΓÇï
+ // Create reply with image.
+ var reply = MessageFactory.Text($"Attachment of {ΓÇïΓÇïΓÇïΓÇïΓÇïattachment.ContentType}ΓÇïΓÇïΓÇïΓÇïΓÇï type and size of {ΓÇïΓÇïΓÇïΓÇïΓÇïresponseMessage.Content.Headers.ContentLength}ΓÇïΓÇïΓÇïΓÇïΓÇï bytes received.");
+ reply.Attachments = new List<Attachment>() {ΓÇïΓÇïΓÇïΓÇïΓÇï
+ GetInlineAttachment()
+ }ΓÇïΓÇïΓÇïΓÇïΓÇï;
+ await turnContext.SendActivityAsync(reply, cancellationToken);
+}ΓÇïΓÇïΓÇïΓÇïΓÇï
+private static Attachment GetInlineAttachment()
+{ΓÇïΓÇïΓÇïΓÇïΓÇï
+ var imagePath = Path.Combine("Files", "ImageFromUser.png");
+ var imageData = Convert.ToBase64String(File.ReadAllBytes(imagePath));
+ return new Attachment
+ {ΓÇïΓÇïΓÇïΓÇïΓÇï
+ Name = @"ImageFromUser.png",
+ ContentType = "image/png",
+ ContentUrl = $"data:image/png;base64,{ΓÇïΓÇïΓÇïΓÇïΓÇïimageData}ΓÇïΓÇïΓÇïΓÇïΓÇï",
+ }ΓÇïΓÇïΓÇïΓÇïΓÇï;
+}ΓÇïΓÇïΓÇïΓÇïΓÇï
+```
+ ### Basic example in C# The following sample shows how to handle file uploads and send file consent requests in the bot's dialog:
@@ -192,20 +233,57 @@ The following sample shows how to handle file uploads and send file consent requ
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
- string filename = "teams-logo.png";
- string filePath = Path.Combine("Files", filename);
- long fileSize = new FileInfo(filePath).Length;
- await SendFileCardAsync(turnContext, filename, fileSize, cancellationToken);
+ if (turnContext.Activity.Attachments?[0].ContentType.Contains("image/*") == true)
+ {
+ // Inline image.
+ await ProcessInlineImage(turnContext, cancellationToken);
+ }
+ else
+ {
+ string filename = "teams-logo.png";
+ string filePath = Path.Combine("Files", filename);
+ long fileSize = new FileInfo(filePath).Length;
+ await SendFileCardAsync(turnContext, filename, fileSize, cancellationToken);
+ }
+}
+private async Task ProcessInlineImage(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
+{
+ var attachment = turnContext.Activity.Attachments[0];
+ var client = _clientFactory.CreateClient();
+ // Get Bot's access token to fetch inline image.
+ var token = await new MicrosoftAppCredentials(microsoftAppId, microsoftAppPassword).GetTokenAsync();
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
+ var responseMessage = await client.GetAsync(attachment.ContentUrl);
+ // Save the inline image to Files directory.
+ var filePath = Path.Combine("Files", "ImageFromUser.png");
+ using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
+ {
+ await responseMessage.Content.CopyToAsync(fileStream);
+ }
+ // Create reply with image.
+ var reply = MessageFactory.Text($"Attachment of {attachment.ContentType} type and size of {responseMessage.Content.Headers.ContentLength} bytes received.");
+ reply.Attachments = new List<Attachment>() { GetInlineAttachment() };
+ await turnContext.SendActivityAsync(reply, cancellationToken);
+}
+private static Attachment GetInlineAttachment()
+{
+ var imagePath = Path.Combine("Files", "ImageFromUser.png");
+ var imageData = Convert.ToBase64String(File.ReadAllBytes(imagePath));
+ return new Attachment
+ {
+ Name = @"ImageFromUser.png",
+ ContentType = "image/png",
+ ContentUrl = $"data:image/png;base64,{imageData}",
+ };
}- private async Task SendFileCardAsync(ITurnContext turnContext, string filename, long filesize, CancellationToken cancellationToken) { var consentContext = new Dictionary<string, string> {
- { "filename", filename
+ {
+ "filename", filename
}, };- var fileCard = new FileConsentCard { Description = "This is the file I want to send you",
@@ -213,82 +291,20 @@ private async Task SendFileCardAsync(ITurnContext turnContext, string filename,
AcceptContext = consentContext, DeclineContext = consentContext, };- var asAttachment = new Attachment { Content = fileCard, ContentType = FileConsentCard.ContentType, Name = filename, };- var replyActivity = turnContext.Activity.CreateReply();
- replyActivity.Attachments = new List<Attachment>() { asAttachment
- };
+ replyActivity.Attachments = new List<Attachment>() { asAttachment };
await turnContext.SendActivityAsync(replyActivity, cancellationToken); }
+```
-protected override async Task OnTeamsFileConsentAcceptAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
-{
- try
- {
- JToken context = JObject.FromObject(fileConsentCardResponse.Context);
-
- string filePath = Path.Combine("Files", context["filename"].ToString());
- long fileSize = new FileInfo(filePath).Length;
- var client = _clientFactory.CreateClient();
- using (var fileStream = File.OpenRead(filePath))
- {
- var fileContent = new StreamContent(fileStream);
- fileContent.Headers.ContentLength = fileSize;
- fileContent.Headers.ContentRange = new ContentRangeHeaderValue(0, fileSize - 1, fileSize);
- await client.PutAsync(fileConsentCardResponse.UploadInfo.UploadUrl, fileContent, cancellationToken);
- }
-
- await FileUploadCompletedAsync(turnContext, fileConsentCardResponse, cancellationToken);
- }
- catch (Exception e)
- {
- await FileUploadFailedAsync(turnContext, e.ToString(), cancellationToken);
- }
-}
-
-protected override async Task OnTeamsFileConsentDeclineAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
-{
- JToken context = JObject.FromObject(fileConsentCardResponse.Context);
-
- var reply = MessageFactory.Text($"Declined. We won't upload file <b>{context["filename"]}</b>.");
- reply.TextFormat = "xml";
- await turnContext.SendActivityAsync(reply, cancellationToken);
-}
-
-private async Task FileUploadCompletedAsync(ITurnContext turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
-{
- var downloadCard = new FileInfoCard
- {
- UniqueId = fileConsentCardResponse.UploadInfo.UniqueId,
- FileType = fileConsentCardResponse.UploadInfo.FileType,
- };
-
- var asAttachment = new Attachment
- {
- Content = downloadCard,
- ContentType = FileInfoCard.ContentType,
- Name = fileConsentCardResponse.UploadInfo.Name,
- ContentUrl = fileConsentCardResponse.UploadInfo.ContentUrl,
- };
-
- var reply = MessageFactory.Text($"<b>File uploaded.</b> Your file <b>{fileConsentCardResponse.UploadInfo.Name}</b> is ready to download");
- reply.TextFormat = "xml";
- reply.Attachments = new List<Attachment> { asAttachment
- };
-
- await turnContext.SendActivityAsync(reply, cancellationToken);
-}
+### Code sample
-private async Task FileUploadFailedAsync(ITurnContext turnContext, string error, CancellationToken cancellationToken)
-{
- var reply = MessageFactory.Text($"<b>File upload failed.</b> Error: <pre>{error}</pre>");
- reply.TextFormat = "xml";
- await turnContext.SendActivityAsync(reply, cancellationToken);
-}
-```
+|**Sample name** | **Description** | **.NETCore** | **Javascript** | **Python**|
+|-|--|--|-|--|
+| File upload | Demonstrates how to obtain file consent and upload files to Teams from a bot. Also, how to receive a file sent to a bot. | [View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/csharp_dotnetcore/56.teams-file-upload) | [View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/javascript_nodejs/56.teams-file-upload) | [View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/python/56.teams-file-upload) |
platform https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/conversation-basics https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/bots/how-to/conversations/conversation-basics.md
@@ -1,24 +1,26 @@
Title: Conversation basics-
-description: How to have a conversation with a Microsoft Teams bot
+description: describes ways to have a conversation with a Microsoft Teams bot
+keyword: conversations basics receive message send message picture message channel data adaptive cards
# Conversation basics [!INCLUDE [pre-release-label](~/includes/v4-to-v3-pointer-bots.md)]
-A conversation is a series of messages sent between your bot and one or more users. There are three kinds of conversations (also called scopes) in Teams:
+A conversation is a series of messages sent between your bot and one or more users. There are three types of conversations, also called scopes in Teams:
-* `teams` Also called channel conversations, visible to all members of the channel.
-* `personal` Conversations between bots and a single user.
-* `groupChat` Chat between a bot and two or more users. Also enables your bot in meeting chats.
+| Conversation type | Description |
+| - | -- |
+| `teams` | Also called channel conversations, visible to all members of the channel. |
+| `personal` | Conversations between bots and a single user. |
+| `groupChat` | Chat between a bot and two or more users. Also enables your bot in meeting chats. |
A bot behaves slightly differently depending on what kind of conversation it is involved in: * Bots in channel and group chat conversations require the user to @ mention the bot to invoke it in a channel.
-* Bots in a one-to-one conversation do not require an @ mention. All messages sent by the user will be routed to your bot.
+* Bots in a one-to-one conversation do not require an @ mention. All messages sent by the user routes to your bot.
To enable your bot in a particular scope, add that scope to your [app manifest](~/resources/schem).
@@ -26,13 +28,13 @@ To enable your bot in a particular scope, add that scope to your [app manifest](
Each message is an `Activity` object of type `messageType: message`. When a user sends a message, Teams posts the message to your bot; specifically, it sends a JSON object to your bot's messaging endpoint. Your bot examines the message to determine its type and responds accordingly.
-Basic conversation is handled through the Bot Framework Connector, a single REST API to enable your bot to communicate with Teams and other channels. The Bot Builder SDK provides easy access to this API, additional functionality to manage conversation flow and state, and simple ways to incorporate cognitive services such as natural language processing (NLP).
+Basic conversations are handled through the Bot Framework Connector, a single REST API. This API enables your bot to communicate with Teams and other channels. The Bot Builder SDK provides easy access to this API, additional functionality to manage conversation flow and state, and simple ways to incorporate cognitive services such as Natural Language Processing (NLP).
## Receive a message To receive a text message, use the `Text` property of the `Activity` object. In the bot's activity handler, use the turn context object's `Activity` to read a single message request.
-The code below shows an example.
+The following code shows an example.
# [C#/.NET](#tab/dotnet)
@@ -117,7 +119,7 @@ async def on_message_activity(self, turn_context: TurnContext):
## Send a message
-To send a text message, specify the string you want to send as the activity. In the bot's activity handlers, use the turn context object's `SendActivityAsync` method to send a single message response. You can also use the object's `SendActivitiesAsync` method to send multiple responses at once. The code below shows an example of sending a message when someone is added to a conversation
+To send a text message, specify the string you want to send as the activity. In the bot's activity handler, use the turn context object's `SendActivityAsync` method to send a single message response. Use the object's `SendActivitiesAsync` method to send multiple responses at once. The following code shows an example of sending a message when someone is added to a conversation.
# [C#/.NET](#tab/dotnet)
@@ -206,19 +208,19 @@ async def on_members_added_activity(
## Teams channel data
-The `channelData` object contains Teams-specific information and is the definitive source for team and channel IDs. You may need to cache and use these ids as keys for local storage. The `TeamsActivityHandler` in the SDK will typically pull out important information from the `channelData` object to make it more easily accessible, however you can always access the original information from the `turnContext` object.
+The `channelData` object contains Teams-specific information and is a definitive source for team and channel IDs. You may need to cache and use these IDs as keys for local storage. The `TeamsActivityHandler` in the SDK, typically pulls out important information from the `channelData` object to make it easily accessible. However, you can always access the original data from the `turnContext` object.
-The `channelData` object is not included in messages in personal conversations since these take place outside of any channel.
+The `channelData` object is not included in messages in personal conversations, as these take place outside of any channel.
A typical channelData object in an activity sent to your bot contains the following information:
-* `eventType` Teams event type; passed only in cases of [channel modification events](~/bots/how-to/conversations/subscribe-to-conversation-events.md)
-* `tenant.id` Azure Active Directory tenant ID; passed in all contexts
+* `eventType` Teams event type; passed only in cases of [channel modification events](~/bots/how-to/conversations/subscribe-to-conversation-events.md).
+* `tenant.id` Azure Active Directory tenant ID, passed in all contexts.
* `team` Passed only in channel contexts, not in personal chat.
- * `id` GUID for the channel
- * `name` Name of the team; passed only in cases of [team rename events](~/bots/how-to/conversations/subscribe-to-conversation-events.md)
-* `channel` Passed only in channel contexts when the bot is mentioned or for events in channels in teams where the bot has been added
- * `id` GUID for the channel
+ * `id` GUID for the channel.
+ * `name` Name of the team; passed only in cases of [team rename events](~/bots/how-to/conversations/subscribe-to-conversation-events.md).
+* `channel` Passed only in channel contexts when the bot is mentioned or for events in channels in teams where the bot has been added.
+ * `id` GUID for the channel.
* `name` Channel name; passed only in cases of [channel modification events](~/bots/how-to/conversations/subscribe-to-conversation-events.md). * `channelData.teamsTeamId` Deprecated. This property is included only for backwards compatibility. * `channelData.teamsChannelId` Deprecated. This property is included only for backwards compatibility.
@@ -254,7 +256,7 @@ Your bot can send rich text, pictures, and cards. Users can send rich text and p
## Adding notifications to your message
-Notifications alert users about new tasks, mentions and comments related to what they are working on, or need to look at by inserting a notice into their Activity Feed. You can set notifications to trigger from your bot message by setting the `TeamsChannelData` objects `Notification.Alert` property to true. Whether or not a notification is raised will ultimately depend on the individual user's Teams settings and you cannot programmatically override these settings. The type of notification will be either a banner or both a banner and an email.
+Notifications alert users about new tasks, mentions, and comments related to what they are working on or need to look at by inserting a notice into their activity feed. You can set notifications to trigger from your bot-message by setting the `TeamsChannelData` objects `Notification.Alert` property to true. Whether or not a notification is raised ultimately depends on the individual user's Teams settings and you cannot programmatically override these settings. The type of notification is either a banner or both a banner and an email.
# [C#/.NET](#tab/dotnet)
@@ -329,17 +331,48 @@ async def on_message_activity(self, turn_context: TurnContext):
## Picture messages
-Pictures are sent by adding attachments to a message. You can find more information on attachments in the [Bot Framework documentation](/azure/bot-service/dotnet/bot-builder-dotnet-add-media-attachments?view=azure-bot-service-3.0&preserve-view=true).
+Pictures are sent by adding attachments to a message. You can find more information on attachments in the [Bot Framework documentation](/azure/bot-service/dotnet/bot-builder-dotnet-add-media-attachments).
-Pictures can be at most 1024×1024 and 1 MB in PNG, JPEG, or GIF format; animated GIF is not supported.
+Pictures can be at most 1024×1024 and 1 MB in PNG, JPEG, or GIF format. Animated GIF is not supported.
-We recommend that you specify the height and width of each image by using XML. If you use Markdown, the image size defaults to 256×256. For example:
+Always specify the height and width of each image by using XML. In Markdown, the image size defaults to 256×256. For example:
* Use - `<img src="http://aka.ms/Fo983c" alt="Duck on a rock" height="150" width="223"></img>` * Don't use - `![Duck on a rock](http://aka.ms/Fo983c)`
+## Adaptive cards
+
+Use the following code to send a simple adaptive card:
+
+```json
+{
+ "type": "AdaptiveCard",
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5",
+ "body": [
+ {
+ "items": [
+ {
+ "size": "large",
+ "text": " Simple Adaptivecard Example with a Textbox",
+ "type": "TextBlock",
+ "weight": "bolder",
+ "wrap": true
+ },
+ ],
+ "spacing": "extraLarge",
+ "type": "Container",
+ "verticalContentAlignment": "center"
+ }
+ ]
+}
+```
+
+To know more about cards and cards in bots, see [cards documentation](~/task-modules-and-cards/what-are-cards.md).
+When a response contains text messages and attachments, both responses are sent separately. The attachment is sent after the text message.
+ ## Code sample
-|**Sample name** | **Description** | **.NETCore** | **Javascript** | **Python**|
+|**Sample name** | **Description** | **.NETCore** | **JavaScript** | **Python**|
|-|--|--|-|--| | Teams Conversation Bot | Messaging and conversation event handling. |[View](https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/csharp_dotnetcore/57.teams-conversation-bot)|[View](https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/javascript_nodejs/57.teams-conversation-bot)| [View](https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/python/57.teams-conversation-bot) |
platform https://docs.microsoft.com/en-us/microsoftteams/platform/build-your-first-app/build-and-run https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/build-your-first-app/build-and-run.md
@@ -8,11 +8,12 @@
# Build and run your first Microsoft Teams app
-You can jump right into Microsoft Teams development by building a personal tab that displays "Hello, World!"
+Start Microsoft Teams development by building a personal tab that displays "Hello, World!".
+Build and run your first Teams app using the following steps:
## 1. Create your app project
-Use the Microsoft Teams Toolkit in Visual Studio Code to set up your first app project.
+Use the Microsoft Teams Toolkit in Visual Studio Code to set up your first app project. Create your app project using the following steps:
1. In Visual Studio Code, select **Microsoft Teams** :::image type="icon" source="../assets/icons/vsc-toolkit.png"::: on the left Activity Bar and choose **Create a new Teams app**. 1. When prompted, sign in with your Microsoft 365 development account.
@@ -35,13 +36,11 @@ If you create a tab during setup, for example, the `App.js` file in the `src/com
### App ID
-Your Teams app ID is needed to configure your app with App Studio. You can find the ID in the `teamsAppId` object, which is located in your project's `package.json` file.
+Configure your app with App Studio using the Teams app ID. Find the ID in the `teamsAppId` object, which is located in your project's `package.json` file.
## 3. Build and run your app
-In the interest of time, you'll build and run your app locally.
-
-(This information is also available in the toolkit `README`.)
+Build and run your app locally to save time. This information is also available in the toolkit `README`. Build and run your app using the following steps:
1. In a terminal, go to the root directory of your app project and run `npm install`. 1. Run `npm start`.
@@ -50,12 +49,17 @@ Once complete, there's a **Compiled successfully!** message in the terminal. You
## 4. Sideload your app in Teams
-Your app is ready to test in Teams. To do this, you must have an account that allows app sideloading. (If you aren't sure you have that, learn about getting a [Teams development account](../build-your-first-app/build-first-app-overview.md#set-up-your-development-account).)
+Your app is ready to test in Teams. To do this, you must have a Microsoft 365 development account that allows app sideloading. For more information on account opening, see [Teams development account](../build-your-first-app/build-first-app-overview.md#set-up-your-development-account).
> [!TIP]
-> Before sideloading your app, check for issues using the [validation feature in App Studio](../concepts/deploy-and-publish/appsource/prepare/submission-checklist.md#teams-app-validation-tool), which is included in the toolkit. Errors must be fixed to successfully sideload the app.
+> Check for issues before sideloading your app, using the [validation feature in App Studio](../concepts/deploy-and-publish/appsource/prepare/submission-checklist.md#teams-app-validation-tool), which is included in the toolkit. Fix the errors to successfully sideload the app.
+
+Sideload your app in Teams using the following steps:
+
+> [!NOTE]
+> To enable sideloading before you sideload your app in Teams, follow the steps in [Turn on app sideloading](../concepts/build-and-test/prepare-your-o365-tenant.md#enable-custom-teams-apps-and-turn-on-custom-app-uploading).
-1. In Visual Studio Code, press the **F5** key to launch a Teams web client.
+1. Select the **F5** key to launch a Teams web client in Visual Studio Code.
1. To display your app content in Teams, specify that where your app is running (`localhost`) is trustworthy: 1. Open a new tab in the same browser window (Google Chrome by default) which opened after pressing **F5**. 1. Go to `https://localhost:3000/tab` and proceed to the page.
platform https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/prepare-your-o365-tenant https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/concepts/build-and-test/prepare-your-o365-tenant.md
@@ -43,6 +43,8 @@ Turn on custom app sideloading for your developer tenant as follows:
4. Toggle **upload custom apps** to the **on** position.
+5. Select **Save** to save the changes.
+ That's it! Your test tenant will now allow custom app sideloading. > [!Note]
platform https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/appsource/prepare/submission-checklist https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/concepts/deploy-and-publish/appsource/prepare/submission-checklist.md
@@ -31,7 +31,7 @@ The app validation tool consists of an [app validator](#teams-app-validator) and
> > * [**App Validator homepage**](https://dev.teams.microsoft.com/appvalidation.html) > * [**Teams Visual Studio Code toolkit**](/toolkit/visual-studio-code-overview.md)
-> * [**App Studio**](/concepts/build-and-test/app-studio-overview.md)
+> * [**App Studio**](../../../build-and-test/app-studio-overview.md)
### Teams app validator
platform https://docs.microsoft.com/en-us/microsoftteams/platform/graph-api/import-messages/import-external-messages-to-teams https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/graph-api/import-messages/import-external-messages-to-teams.md
@@ -147,7 +147,8 @@ HTTP/1.1 202 Accepted
After the team and channel have been created, you can begin sending back-in-time messages using the `createdDateTime` and `from` keys in the request body. **NOTE**: messages imported with `createdDateTime` earlier than the message thread `createdDateTime` is not supported. > [!NOTE]
-> createdDateTime must be unique across messages in the same thread.
+> * `createdDateTime` must be unique across messages in the same thread.
+> * `createdDateTime` supports timestamps with milliseconds precision. For example, if the incoming request message has the value of `createdDateTime` set as *2020-09-16T05:50:31.0025302Z*, then it would be converted to *2020-09-16T05:50:31.002Z* when the message is ingested.
#### Request (POST message that is text-only)
platform https://docs.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/graph-api/rsc/resource-specific-consent.md
@@ -46,7 +46,7 @@ The steps for enabling RSC in your application are as follows:
## Configure group owner consent settings in the Azure AD portal
-You can enable or disable [group owner consent](/azure/active-directory/manage-apps/configure-user-consent#configure-group-owner-consent-to-apps-accessing-group-data) directly within the Azure portal:
+You can enable or disable [group owner consent](/azure/active-directory/manage-apps/configure-user-consent-groups?tabs=azure-portal) directly within the Azure portal:
> [!div class="checklist"] >
@@ -56,7 +56,7 @@ You can enable or disable [group owner consent](/azure/active-directory/manage-a
![azure rsc configuration](../../assets/images/azure-rsc-configuration.png)
-To enable or disable group owner consent within the Azure portal using PowerShell, follow the steps outlined in [Configure group owner consent using PowerShell](/azure/active-directory/manage-apps/configure-user-consent#configure-group-owner-consent-using-powershell).
+To enable or disable group owner consent using PowerShell, follow the steps outlined in [Configure group owner consent using PowerShell](/azure/active-directory/manage-apps/configure-user-consent-groups?tabs=azure-powershell).
## Register your app with Microsoft identity platform via the Azure AD portal
platform https://docs.microsoft.com/en-us/microsoftteams/platform/samples/app-templates https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/samples/app-templates.md
@@ -20,6 +20,12 @@ App templates are production-ready apps for Microsoft Teams that are community d
* **Customizable and extensible:** While all app templates are ready to deploy as they are, we provide the entire code base and deployment scripts so that you can easily customize or extend them to fit your unique needs. * **Detailed documentation & support:** All app templates are accompanied by end-to-end documentation on solution architecture, deployment, and configuration steps. The repositories are monitored as well, so please report any issues you encounter by raising an Issue on GitHub.
+## Adoption Bot &#9734;
+
+Adoption Bot is a user care chat bot built with Power Virtual Agent for Teams (PVA). It can be considered as the PVA version of FAQPlus. Adoption Bot answers 100+ common questions about Microsoft 365 and Teams. You can edit the included topics, add your own topics, and ingest existing FAQs. If users need additional help, Adoption Bot can connect them to experts or even be extended to open service tickets with premium flow connectors.
+
+[Get it on GitHub](https://github.com/OfficeDev/microsoft-teams-apps-adopt-bot)
+ ## Appointment Manager &#9734; Appointment Manager is a Teams app template to help businesses create, manage, and conduct virtual appointments with consumers through Teams. New appointment requests from consumers are visible in Teams channels, where they can quickly be assigned and reassigned to staff in a team. Appointment requests can be viewed at team or personal levels through custom tabs. Every appointment is associated with a Teams online meeting, hence the staff and consumers can easily join the meeting at the scheduled time.
platform https://docs.microsoft.com/en-us/microsoftteams/platform/tabs/design/tabs-mobile https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/tabs/design/tabs-mobile.md
@@ -130,3 +130,7 @@ For authentication to work on mobile clients, you must upgrade you Teams JavaScr
### Low bandwidth and intermittent connections Mobile clients regularly need to function with low bandwidth and intermittent connections. Your app should handle any timeouts appropriately by providing a contextual message to the user. You should also user progress indicators to provide feedback to your users for any long-running processes.+
+> [!NOTE]
+> Tabs are enabled on mobile only after the application is added to an allow list, based on the input of the approval team.
+> To check mobile responsiveness, reach out to teamsubm@microsoft.com.
platform https://docs.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/tabs/how-to/authentication/auth-aad-sso.md
@@ -9,7 +9,7 @@ keywords: teams authentication SSO AAD single sign-on api
Users sign in to Microsoft Teams via their work, school, or Microsoft accounts (Office 365, Outlook, etc). You can take advantage of this by allowing a single sign-on to authorize your Microsoft Teams tab (or task module) on desktop or mobile clients. Thus, if a user consents to use your app, they wonΓÇÖt have to consent again on another device ΓÇö they will be signed in automatically. In addition, we prefetch your access token to improve performance and load times.
->[!NOTE]
+> [!NOTE]
> **Teams mobile client versions supporting SSO** > > Γ£öTeams for Android (1416/1.0.0.2020073101 and later)
@@ -18,12 +18,11 @@ Users sign in to Microsoft Teams via their work, school, or Microsoft accounts (
> > For the best experience with Teams, please use the latest version of iOS and Android.
->[!NOTE]
+> [!NOTE]
> **Quickstart** > > The simplest path to getting started with tab SSO is with the Microsoft Teams Toolkit for Visual Studio Code. [Learn more](../../../toolkit/visual-studio-code-tab-sso.md) - ## How SSO works at runtime The following diagram shows how the SSO process works:
@@ -199,3 +198,6 @@ Another approach for getting additional Microsoft Graph scopes is to present a c
### Non-Azure AD Authentication The above-described authentication solution only works for apps and services that support Azure AD as an identity provider. Apps that want to authenticate using non-Azure AD based services need to continue using the pop-up-based [web authentication flow](~/concepts/authentication.md).+
+> [!NOTE]
+> SSO is supported for customer owned apps within the Azure AD B2C tenants.
platform https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-outgoing-webhook https://github.com/MicrosoftDocs/msteams-docs/commits/master/msteams-platform/webhooks-and-connectors/how-to/add-outgoing-webhook.md
@@ -1,57 +1,93 @@
Title: Add custom bots to Microsoft Teams with outgoing webhooks-
-description: how to add an outgoing webhook
-keywords: teams tabs outgoing webhook*
+description: describes how to add an outgoing webhook
+keywords: teams tabs outgoing webhook actionable message verify webhook
-# Add custom bots to Microsoft Teams with outgoing webhooks
+# Add custom bots to Teams with outgoing webhooks
## What are outgoing webhooks in Teams?
-Webhooks are a great way for Teams to integrate with external apps. A webhook is essentially a POST request sent to a callback URL. In Teams, outgoing webhooks provide a simple way to allow users to send messages to your web service without having to go through the full process of creating bots via the [Microsoft Bot Framework](https://dev.botframework.com/). Outgoing webhooks post data from Teams to any chosen service capable of accepting a JSON payload. Once an outgoing webhook is added to a team, it acts like bot, listening in channels for messages using **\@mention**, sending notifications to external web services, and responding with rich messages that can include cards and images.
+Webhooks are an eminent way for Teams to integrate with external apps. A webhook is essentially a POST request sent to a callback URL. Outgoing webhooks allow users to send messages to your web service without going through the full process of creating bots via the [Microsoft Bot Framework](https://dev.botframework.com/).
+
+Outgoing webhook sends data from Teams to any chosen service capable of accepting a JSON payload. After adding the outgoing webhooks to a team, it acts as a bot and looks for messages in channels using **\@mention**. It sends notifications to external web services and responds with rich messages, which include cards and images.
## Outgoing webhook key features | Feature | Description | | - | -- |
-| Scoped Configuration| Webhooks are scoped at the team level. YouΓÇÖll need to go through the setup process for each team you want to add your outgoing webhook to. |
-| Reactive Messaging| Users must use @mention for the webhook to receive messages. Currently users can only message an outgoing webhook in public channels and not within the personal or private scope |
-|Standard HTTP message exchange|Responses will appear in the same chain as the original request message and can include any Bot Framework message content (rich text, images, cards, and emojis). **Note**: Although outgoing webhooks can use cards, they cannot use any card actions except for `openURL`.|
-| Teams API method support|In Teams, outgoing webhooks send an HTTP POST to a web service and process a response back. They cannot access any other APIs like retrieve the roster or list of channels in a team.|
+| Scoped configuration| Webhooks are scoped at the team level. You must go through the setup process for each team where you want to add your outgoing webhook. |
+| Reactive messaging| Users must use @mention for the webhook to receive messages. Currently, users can only message an outgoing webhook in public channels and not within the personal or private scope. |
+|Standard HTTP message exchange|Responses appear in the same chain as the original request message and can include any bot framework message content, for example, rich text, images, cards, and emojis. Although outgoing webhooks can use cards, they cannot use any card actions except for `openURL`.|
+| Teams API method support|Outgoing webhook sends an HTTP POST to a web service and process a response back. They cannot access any other APIs like retrieve the roster or list of channels in a team.|
+
+## Creating actionable messages
+
+The connector cards include three visible buttons on the card. Each button is defined in the `potentialAction` property of the message by using `ActionCard` actions. Each `ActionCard` contains an input type; a text field, a date picker, or a multi-choice list. Each `ActionCard` action has an associated action, for example, `HttpPOST`.
+
+Connector cards support three types of actions:
+
+| Action | Description |
+| - | -- |
+| `ActionCard` |Presents one or more input types and associated actions.|
+| `HttpPOST` | Sends a POST request to a URL. |
+| `OpenUri` | Opens a URI in a separate browser or app, optionally targets different URIs based on operating systems.|
+
+The `ActionCard` action supports three input types:
+
+| Input type | Description |
+| - | -- |
+| `TextInput` | A single-line or multiline text field with an optional length limit. |
+| `DateInput` | A date selector with an optional time selector. |
+| `MultichoiceInput` | A specified list of choices, offering either a single selection or multiple selections.|
+
+`MultichoiceInput` supports a `style` property that controls the display of a fully expanded list. The default value of `style` depends on the `isMultiSelect` value.
+
+| `isMultiSelect` value | `style` default value |
+| | |
+| `false` or not specified | The default style is `compact`|
+| `true` | The default style is `expanded` |
-## Adding outgoing webhook processing to your app
+> [!NOTE]
+> * Enter both `"isMultiSelect": true` and `"style": true`, if you want the multi-select list to be displayed in a compact style.
+> * Selecting `compact` for the `style` property in Teams is the same as selecting `normal` for the `style` property in Microsoft Outlook.
+> * Webhooks support only Office 365 message back cards and adaptive cards.
+
+For all other details about connector card actions, see **[Actions](/outlook/actionable-messages/card-reference#actions)** in the actionable message card reference.
+
+## Adding outgoing webhooks to your app
**Scenario**: Push change status notifications on a Teams channel database server to your app. **Example**: You have a line-of-business app that tracks all CRUD operations made to employee records by Teams channel HR users across an Office 365 tenancy. ### 1. Create a URL on your app's server to accept and process a POST request with a JSON payload
-Your service will receive messages in the standard Azure bot service messaging schema. The Bot Framework connector is a RESTful service that enables your service to process the interchange of JSON formatted messages via HTTPS protocols as documented in the [Azure Bot Service API](/bot-framework/rest-api/bot-framework-rest-connector-api-reference). Alternatively, you can follow the [Microsoft Bot Framework SDK] to process and parse messages. *See also* [About Azure Bot Service](/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0).
+Your service receives messages in a standard Azure bot service messaging schema. The bot framework connector is a RESTful service that empowers your service to process the interchange of JSON formatted messages via HTTPS protocols as documented in the [Azure Bot Service API](/bot-framework/rest-api/bot-framework-rest-connector-api-reference). Alternatively, you can follow the [Microsoft Bot Framework SDK] to process and parse messages. See also [About Azure Bot Service](/azure/bot-service/bot-service-overview-introduction).
+
-Outgoing webhooks are scoped to the `team` level and are visible to all members of the team. Just like a bot, users are required to **\@mention** the name of the outgoing webhook to invoke it in the channel.
+Outgoing webhooks are scoped to the `team` level and are visible to all the team members. Just like a bot, users need to **\@mention** the name of the outgoing webhook to invoke it in the channel.
### 2. Create a method to verify the outgoing webhook HMAC token #### HMAC signature for testing with code example
-Using example of inbound message and id : "contoso" of SigningKeyDictionary of {"contoso", "vqF0En+Z0ucuRTM/01o2GuhMH3hKKk/N2bOmlM31zaA=" }.
+Using example of inbound message and id: "contoso" of SigningKeyDictionary of {"contoso", "vqF0En+Z0ucuRTM/01o2GuhMH3hKKk/N2bOmlM31zaA=" }.
Use the value "HMAC 03TCao0i55H1eVKUusZOTZRjtvYTs+mO41mPL+R1e1U=" in the authorization of request header.
-To ensure that your service is receiving calls only from actual Teams clients, Teams provides an HMAC Code in the HTTP `hmac` header that should always be included in your authentication protocol.
+To ensure that your service is receiving calls only from actual Teams clients, Teams provides an HMAC code in the HTTP `hmac` header. Always included the code in your authentication protocol.
-Your code should always validate the HMAC signature included in the request:
+Your code must always validate the HMAC signature included in the request:
-* *Generate* the HMAC token from the request body of the message. There are standard libraries to do this on most platforms (*see* [Crypto](https://nodejs.org/api/crypto.html#crypto_crypto) for Node.js or *see* [Teams Webhook Sample](https://github.com/OfficeDev/microsoft-teams-sample-outgoing-webhook/blob/23eb61da5a18634d51c5247944843da9abed01b6/WebhookSampleBot/Models/AuthProvider.cs) for C\#). Microsoft Teams uses standard SHA256 HMAC cryptography . You will need to convert the body to a byte array in UTF8.
-* *Compute* the hash from the byte array of the security token **provided by Teams** when you registered the outgoing webhook in the Teams client]. *See* [Create an outgoing webhook](#create-an-outgoing-webhook), below.
-* *Convert* the hash to a string using UTF-8 encoding.
-* *Compare* the string value of the generated hash with the value provided in the HTTP request.
+* Generate the HMAC token from the request body of the message. There are standard libraries to do this on most platforms (see [Crypto](https://nodejs.org/api/crypto.html#crypto_crypto) for Node.js or see [Teams Webhook Sample](https://github.com/OfficeDev/microsoft-teams-sample-outgoing-webhook/blob/23eb61da5a18634d51c5247944843da9abed01b6/WebhookSampleBot/Models/AuthProvider.cs) for C\#). Microsoft Teams uses standard SHA256 HMAC cryptography. You need to convert the body to a byte array in UTF8.
+* Compute the hash from the byte array of the security token **provided by Teams** when you registered the outgoing webhook in the Teams client]. See [Create an outgoing webhook](#create-an-outgoing-webhook).
+* Convert the hash to a string using UTF-8 encoding.
+* Compare the string value of the generated hash with the value provided in the HTTP request.
### 3. Create a method to send a success or failure response
-Responses from your outgoing webhook will appear in the same reply chain as the original message. When the user performs a query, Microsoft Teams issues a synchronous HTTP request to your service and your code will have 5 seconds to respond to the message before the connection times out and terminates.
+Responses from your outgoing webhooks appear in the same reply chain as the original message. When the user performs a query, Microsoft Teams issues a synchronous HTTP request to your service and your code gets five seconds to respond to the message before the connection times out and terminates.
### Example response
@@ -64,18 +100,18 @@ Responses from your outgoing webhook will appear in the same reply chain as the
## Create an outgoing webhook
-1. Select the appropriate team and select **Manage team** from the (&#8226;&#8226;&#8226;) drop-down menu.
+1. Select the appropriate team and choose **Manage team** from the (&#8226;&#8226;&#8226;) drop-down menu.
1. Choose the **Apps** tab from the navigation bar. 1. From the window's lower right corner select **Create an outgoing webhook**. 1. In the resulting popup window complete the required fields: >* **Name** - The webhook title and @mention tap.
->* **Callback URL** - The HTTPS endpoint that accepts JSON payloads and will receive POST requests from Teams.
->* **Description** - A detailed string that will appear in the profile card and the team-level App dashboard.
->* **Profile Picture** (optional) an app icon for your webhook.
->* Select the **Create** button from lower right corner of the pop-up window and the outgoing webhook will be added to the current team's channels.
->* The next dialog window will display an [Hash-based Message Authentication Code (HMAC)](https://security.stackexchange.com/questions/20129/how-and-when-do-i-use-hmac/20301) security token that will be used to authenticate calls between Teams and the designated outside service.
->* If the URL is valid and the server and client authentication tokens are equal (i.e., an HMAC handshake), the outgoing webhook will be available to the team's users.
+>* **Callback URL** - The HTTPS endpoint that accepts JSON payloads and receives POST requests from Teams.
+>* **Description** - A detailed string that appear in the profile card and the team-level App dashboard.
+>* **Profile Picture** an optional app icon for your webhook.
+>* Select the **Create** button from the lower right corner of the pop-up window and the outgoing webhook are added to the current team's channels.
+>* The next dialog window displays an [Hash-based Message Authentication Code (HMAC)](https://security.stackexchange.com/questions/20129/how-and-when-do-i-use-hmac/20301) security token that is used to authenticate calls between Teams and the designated outside service.
+>* The outgoing webhook is available to the team's users, only if the URL is valid and the server and client authentication tokens are equal for example, an HMAC handshake.
## Code samples