Adaptive Cards

In the first part of the series I wrote a general overview of Message and Adaptive Cards, their brief history and purpose. This part is focused only on Message Cards – the technology from which it all begun and that is still available to use although recommendation is to move to Adaptive Cards.

Message Cards – introduction

Message Cards are created using a declarative JSON-format code. Then the definition is parsed by the SDK into a nice looking part of UI.

They can be used today still in Outlook (both Desktop and Browser based):

Message Card in Outlook
Message Card in Outlook

I doubt if it will be ever possible to use them in Outlook Mobile (Adaptive Cards are already there), plus in Microsoft Teams, sent by Flow or Bot, or via any application through a defined webhook:

Message Card in Microsoft Teams
Message Card in Microsoft Teams

JSON code that defines card is full of options. However it’s main structure consist of two areas: Card definition and Sections.

{
    "@type": "MessageCard",
    "@context": "https://schema.org/extensions",
    "summary": "",
    "themeColor": "",
    "title": "Card created: \"This is just a test\"",
    "sections": [
        {
                  …
        },
        "potentialAction": [
            {
                    …
            }
        ]
    ]
}
Areas in the Message Card
Areas in the Message Card

In Card’s information section you can define basics of your card. These are:

  1. title
  2. summary – property used by Outlook.
  3. themeColor – this is the colorful line on the left of your card. According to documentation, it is advised to use it to brand them e.g. to your organizational colors, but not to indicate status.
  4. hideOriginalBody – again, property used by Outlook.
  5. text – an additional block of text displayed using a regular font below title.

In Section, you can build blocks of data:

  1. facts –  a construct allowing to display data in organized way – a table.
  2. activity – constructed from image, title, subtitle and text.
  3. text – again, a block of text
  4. image 
  5. heroImage – different from regular image, as it displays full-width on a card.
  6. potentialAction – block dedicated for actions (described below). Can also be defined outside “Section” area.

Remember!

You can only use once each type of property in a single “Section” object, however you can have multiple objects (since Section is an array). Moreover – images cannot be defined via URI. It has to be a path to a physical image anonymously accessible (or where currently logged in user has access).

For Potential actions you can choose between the following types of actions:

  1. OpenUri
  2. HttpPost
  3. ActionCard
  4. InvokeAddInCommand
  5. ActionRequest (new version of old Transaction)

Again, there can be more than one action, since potentialAction is an array.

Anytime you would like to use “text” property remember, you can use markdown to format it too! (https://docs.microsoft.com/en-us/outlook/actionable-messages/message-card-reference#text-formatting)

There are two interesting types of actions: ActionCard, which allows to display a “sub card” with form fields and other actionable items. And ActionRequest – activity allowing payment functionalities right from the card, without a need for pushing user to leave our app.

For more information about the Message Cards structure, I recommend reading the documentation:

Important!

Note, that Message Cards are getting deprecated and replaced by their younger successor: Adaptive Cards. Microsoft recommends to migrate where possible from Message to Adaptive Cards format: https://docs.microsoft.com/en-us/outlook/actionable-messages/adaptive-card

Message Cards administration

Please note that administrator can disable rendering of Message Cards both in Outlook and Teams, by using Set-OrganizationConfig cmdlet: https://docs.microsoft.com/en-us/powershell/module/exchange/organization/set-organizationconfig

Working exampe (aka demo ;))

The solution I am about to show you is connecting SharePoint workflows (using 3rd party solution – Nintex) and Microsoft Teams, making this process running in a truly digital workplace experience mode. Let’s see how it works:

  1. In SharePoint user is creating an item, that requires approval
  2. Workflow assigns a task and in that moment it also sends, via a Teams webhook, prepared Message Card JSON.
  3. Approver therefore can complete a task any way he likes: through a native, SharePoint task, via an Actionable Message in Outlook or using Microsoft Teams.
  4. Let’s focus on Teams – approver decides, and clicks related outcome.
  5. Message Card is refreshed and instead of the previous form, now shows a confirmation information.

The workflow

SharePoint workflow is created with Nintex. It is quite simple: once an item is created it assignes a task to approver and in the same time it creates a Message Card in Teams for approval using that channel:

Nintex Workflow assigning task and sending Message Card
Nintex Workflow assigning task and sending Message Card

Posting a Message Card to Microsoft Teams

To be able to post a Message Card you must first create a Webhook for a channel. To do that first go to “Manage team” page of a team you want to post a message to:

Adding webhook to Teams, part 1
Adding webhook to Teams, part 1

Next go to “Apps” tab and click the “More apps” button:

Adding webhook to Teams, part 2
Adding webhook to Teams, part 2

Next type “Webhook” in the search menu and click the tile that appears:

Adding webhook to Teams, part 3
Adding webhook to Teams, part 3

Then click the button “Open” and after that select the channel, to which you want to post a Message Card and finally the button “Set up”:

Adding webhook to Teams, part 4
Adding webhook to Teams, part 4

Finally define webhook’s name (it will be displayed as the author of all messages), upload icon (avatar) and hit “Create”:

Adding webhook to Teams, part 5
Adding webhook to Teams, part 5

After it is created, copy the generated URL and “Done”:

Adding webhook to Teams, part 6
Adding webhook to Teams, part 6

Important!

The URL is the one that the “Web request” action in my workflow will use to post message to.

Next what has to be defined is the Message Card JSON. I have created a code using the Playground and then put dynamic values inside it, so that once workflow replaces them with actual data, the Card is really adjusted to the particular needs. Withing the “potentialActions” section I put buttons to Approve/ Reject request, which once clicked are executing HttpPOST action and is sending , along with the Outcome and Comments, SharePoint Task ID:

{
    "@@type": "ActionCard",
    "name": "Approve",
    "inputs": [
        {
            "@@type": "TextInput",
            "id": "ApprovalComment",
            "isMultiline": true,
            "title": "Comment (optional)"
        }
    ],
    "actions": [
        {
            "@@type": "HttpPOST",
            "name": "Submit",
            "target": "FLOW URL",
            "headers": [
                {
                    "name": "content-type",
                    "value": "application/json"
                },
                {
                    "name": "authorization",
                    "value": ""
                }
            ],
            "bodyContentType": "application/json",
            "body": "{\"approved\":true, \"comment\":\"{{ApprovalComment.value}}\", \"taskID\":10"
        }
    ]
}

In the end, posted Message Card looks like below:

Message Card posted by Nintex via webhook
Message Card posted by Nintex via webhook

Registering the outcome and refresing the Card

To handle actions from Message Card I decided to use Microsoft Flow that is triggered on incoming Web Request, using the following schema:

Microsoft Flow trigger for incoming web request
Microsoft Flow trigger for incoming web request
{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "inputParameters": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "value": {
                        "type": "string"
                    }
                },
                "required": [
                    "id",
                    "value"
                ]
            }
        },
        "actionId": {
            "type": "string"
        },
        "potentialAction": {
            "type": "string"
        },
        "integrationId": {
            "type": "string"
        },
        "meta": {
            "type": "string"
        },
        "clientInfo": {
            "type": "object",
            "properties": {
                "locale": {
                    "type": "string"
                },
                "country": {
                    "type": "string"
                },
                "platform": {
                    "type": "string"
                },
                "clientVersion": {
                    "type": "string"
                }
            }
        }
    }
}

Next I am parsing property “Body” to get outcome, comment and taskID, using the following schema:

Parsing "Body" from Message Card
Parsing “Body” from Message Card

Next, based on the outcome, Flow is either updating Task Item to “Approved” or “Rejected”:

Microsoft Flow updating SharePoint task
Microsoft Flow updating SharePoint task

Now the “key” functionality: response being sent to the Message Card. As it can be read here: https://docs.microsoft.com/en-us/outlook/actionable-messages/message-card-reference#refresh-cards and here: https://docs.microsoft.com/en-us/outlook/actionable-messages/message-card-reference#reporting-an-actions-execution-success-or-failure to update a Card it has to receive a request with the following Header keys:

  1. CARD-UPDATE-IN-BODY – true|false, whether to replace card contents
  2. CARD-ACTION-STATUS – message shown as comment, below the card.

If key “CARD-UPDATE-IN-BODY” is set to “true” Card is expecting contents of a new card to be sent out. To build the Message Card to replace “Request” one, try to put as much details in the “body” parameter of the “Request” card so that later you can use them in the Flow to build the “Confirmation” one 🙂

Important!

If you see “@” in any attribute of the Message Card JSON body in your Flow, escape it with additional “@”, to make it double “@@”. Without that you will not be able to save/ execute the Flow.

Working solution

Below you can find animation showing how the whole solution works!

Message Card in Teams
Message Card in Teams

What I learnt?

  1. You can’t mention anyone using Message Card
  2. You can’t post Message Card in a private message
  3. You can’t get user context who clicks the button and pass it to Flow

Thank you for reaching that far! This post is a second one in series in which you can learn about:

  1. Introduction to Adaptive Cards
  2. Message Cards – case study and how-to
  3. Adaptive Cards – case study and how-to
  4. What’s ahead in 2.0 (hopefully with examples :))

Would you like to learn more about Adaptive Cards? Contact me or leave a comment.