Create your own actionable messages for Flow Approvals

Posted by

This is part 2 of the blog post series ‘Take Full Control of Your Flow Approvals’. In part 1 we explored the data model for Approvals in the CDS for Apps. We will use this “infrastructure” to extend it with our own logic and customizations. The standard actionable messages for Flow Approvals have some limitations, so we are going to create our own actionable messages to overcome these limitations. The following features we are going to support:
– Set Reason field as required in case of Reject
– Reassign approval from the actionable message
– MFA for Flow Approvals

But first we have to register our “Approval service” with Microsoft for securing the actionable messages. This will enable the verification of the sender (authorization) and the identity of the user that took the action (authentication ). So we can be sure that only the “owner” of the Approval Request (the assignee) will be able to see and act on the actionable message. When the email is forwarded to someone else, the actionable message is disabled and not shown to the receiver. Go to the Developer Dashboard and add a New Provider.

Add a friendly name for the provider, the Sender email address(es) and the Target URLs: this will be the base URL of the receiving Flow that we are going to call with the Action.Http from the message.

Choose as Scope of submission: My Mailbox (auto-approved), check the terms and Save.
The Provider Id (originator) we will need to include in the JSON of the actionable message, so the provider can be identified.

With the help of the Adaptive Cards Designer I’m able to recreate the Approval actionable message and modify it. We want to set the Reason field as required in case of Reject. With the current version of the Adaptive Card framework client side validation is not possible. Basic Input Validation will be part of version 1.2 that is in beta now. So we have to do server side validation in our receiving Flow and update the actionable message when the Reason field does not contain data in case of Reject as response.

Now let’s take a look at the JSON of this custom actionable message. We add the ‘originator’ key and set the value based on the Provider Id from the Provider registration we did before.

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.0",
  "originator": "abcdefgh-1234-5678-abcd-f696d7890e00",
    "body": [

Next thing to do is configuring the actions. We’re going to use the Action.Http for a POST request to Flow. We include the response and the value of the input field for the reason (Input value substitution) into the ‘body’ key. See for more information: Outlook-specific Adaptive Card properties and features.
Note: The ‘Authorization’ header should be empty to be able to work with Flow.

{
                      "type": "Action.Http",
                      "title": "Submit",
                      "method": "POST",
                      "url": "https://prod-117.westeurope.logic.azure.com:443/workflows/...",
                      "headers": [
                        {
                          "name": "Authorization",
                          "value": ""
                        }
                      ],
                      "body": "{'response':'Reject','reason':'{{reasonInput.value}}','userEmail':'admin@CRM123456.onmicrosoft.com'}"
                    }

In the receiving Flow we parse the JSON of the body to use the keys as dynamic content in the Flow.

Based on the response and reason values, we decide how the Response actions are configured.

We give a 406 (Not Acceptable) as Status Code and the error code ‘Reason is required’ back as response to the actionable message if the reason is empty.

In this way we make sure that a rejection is only processed when the Reason field is not empty.

17 comments

  1. Great series! However I’m fairly new to writing my own adaptive cards. Could you provide the JSON?

  2. Thanks for sharing this. Could you explain a little further about what the HTTP POST URL should be by taking the example of a flow? And also while registering for a new provider, what should be target URL be? I am working primarily with flows, so i registered https://australia.flow.microsoft.com as the Target URL. Is this right or am i missing something?

  3. Hi Stefan,

    Thanks for your post.

    I’m currently working on an approval flow using Outlook actionable message.

    I have created an Outlook actionable message via Ms Flow and registered it on the “Actionable Email Developer Dashboard” with “scope of submission” -> ‘Organization’

    The email containing the actionable message is received by different company members and renders correctly. However, when clicking to take any action I get the following message => “Target URL is not allowed”

    All previous tests worked very well when messages were sent from my email to my email. I could take action and update the message. But now it does not work anymore.

    Here are the different steps:

    – The requester fills a form in a model-driven app (PowerApps)
    – The requester then click on a custom button in the Model-Driven app to trigger a Flow HTTP Request
    – An email actionable message is then sent to the appropriate person to take action Until that step, all good, no problem.

    Then the person receiving the email can click on the actionable message to take action. The message contains an ‘approve’ button that should trigger a Flow HTTP Request That’s where the problem is… It never triggers the Flow and the error message shows “Target URL … is not allowed” All Flows have been shared with all parties. Both actions have been registered on the “Actionable Email Developer Dashboard”

    In the JSON object the token has been placed as the value for the ‘Originator’ key

    “actions”: [
    {
    “type”: “Action.Http”,
    “title”: “Send”,
    “method”: “POST”,
    “url”: “https://prod-00.westus.logic.azure.com:999/workflows”,
    “body”: “{\”comment\”:\”{{ApproveComment.value}}\”}”,
    “headers”: [
    {
    “name”: “Authorization”,
    “value”: “”
    }
    ]
    }
    ],
    “$schema”: “http://adaptivecards.io/schemas/adaptive-card.json”
    }
    },
    The object that should trigger the second Flow HTTP Request is as the snippet above, with a ‘headers’ key and ‘Authorization’, ‘value’ set to an empty string.

    So, what did I do wrong? What should I do to have the second Flow working?

    Thanks for the help

    1. Hi David,

      You should use the complete HTTP POST URL of the trigger ‘When a HTTP request is received’.
      Please copy the complete HTTP POST URL and paste it as value for the ‘url’ key in the JSON.

      Hope it helps.

      1. Thanks Stefan for your reply.

        That’s what I did, I copied the entire URL. I just truncated it in my post.
        I keep getting the message “Target URL … not allowed”
        When the scope was myMailbox, all worked well. When I changed the scope to Organization, the actionable message stopped being reactive.
        The actionable message renders correctly in any mailbox of the organization member but no action can be taken.

        I have followed instructions in https://docs.microsoft.com/en-us/outlook/actionable-messages/ (well, I think so…) and did intensive research on the web but couldn’t find a solution.

          1. Is the method of the ‘When a HTTP request is received’ trigger set to POST?
            Are the Flow IP addresses whitelisted? Are you using Azure API management to secure the Flow trigger?
            Doesn’t it work with any Outlook client (web, desktop, mobile)?
            Is the Sender email address from which actionable emails will originate listed in the Provider registration at the Actionable Email Developer Dashboard?

          2. Hey Stefan,

            Thanks a lot for your reaction and your questions/suggestions.

            ‘When a HTTP request is received’ trigger set to POST? ==> Yes it is
            Flow IP addresses whitelisted? ==> No, looking into it.

            Are you using Azure API management to secure the Flow trigger? ==> No. Is it a requirement?

            Doesn’t it work with any Outlook client (web, desktop, mobile)? ==> It doesn’t even render at all on mobile devices. The adaptive card displays well on web and desktop but no action can be triggered. It worked well however when scope was set to ‘My Mailbox” during registration.

            Sender email address from which actionable emails will originate listed in the Provider registration at the Actionable Email Developer Dashboard? ==> Yes, the email address used to register the actionable message is the one used to connect the module and send the email via Flow.

Leave a Reply

Your email address will not be published. Required fields are marked *