Actionable Message And SharePoint Online

Introduction

This purpose and objective of this article is to explain about the integration of Outlook actionable message and SharePoint online. Before starting the detailed implementation, we will talk about what  Actionable Message is here.

What Is Actionable Message?

Actionable message is a message where a user can perform an action (like approval, site object creation, granting permission etc.) from the outlook e-mail or using team. For the user, there is no need to go to any other application and  they can perform the desired action from e-mail/Team itself. 

A scenario where it will be helpful: Suppose an employee submits a vacation request in the system and the approver is at a remote location or doesn't have application access to approve the request. In those scenarios, the approver will approve the request from e-mail.

We can perform the synchronous and asynchronous action both by using Actionable message. We can perform Asynchronous action with the help of Azure Functions.

Whether users are filling out a survey, approving a vacation request, or updating a purchase order, Actionable Messages enable the user to take quick actions right from within Outlook and Teams.

https://messagecardplayground.azurewebsites.net/ is the site to design the actionable message.

I have used O365 Flow to send the actionable message to the user. We can use other mediums as well to send the actionable message. Following are the other ways to send the message,

Prerequisite

Reader should have basic knowledge about SharePoint, Azure Function & MS Flow.

Sample Scenario

User wants to create a request on the approval of the site collection admin. User will make a request in a SharePoint List and Flow will trigger the event on the new item creation to send the actionable message to site collection admin. Admin can approve/reject the request from the e-mail. Following tool integration, we have used:

  • SharePoint Online – SharePoint online is used to create a request, create a new list.
  • Outlook Actionable Message – To send the actionable message for quick action
  • O365 Flow – To send the e-mail and trigger the SharePoint list new item creation event
  • Azure Function – Azure Function is used to expose SharePoint operations as a serverless service which would be consumed as an endpoint in the post action of actionable message. Actionable message requires an endpoint to perform the post action.

Note

In case your SharePoint operation is time consuming like site provisioning etc., then I am suggesting to include an optional tool, Azure Queue, to process the request asynchronously. In the above mentioned scenario, I have used Synchronous operation so I dod not use Azure Queue here.

Technical Diagram

 

 SharePoint
Implementation Steps

 

Step 1

Register the JSON Actionable Message using the below mentioned link:

To test and publish actionable messages from your service, you need to provide certain information to Microsoft to enable actionable message functionality for emails. The developer dashboard helps user to submit and track status of your submission via the web portal.

Step 2

After registering the actionable message, you will get the Provider ID (originator) which will be used while composing the actionable message for identification purposes and to check if JSON is registered or not.

Step 3

Create a SharePoint List with title “ListCreationRequest”  having the following columns to track the user requests:

  • Requestor – Who is making the request
  • ListName – Title of the List
  • Status -Status of the request
  • Comments – If there are any comments against the request

 SharePoint

Step 4

Create an Azure function and publish to the Azure environment.

  1. using System.Net;  
  2. using Microsoft.SharePoint.Client;  
  3. public static async Task < HttpResponseMessage > Run(HttpRequestMessage req, TraceWriter log) {  
  4.         string siteURL = "https://xxxxxxx";  
  5.         string userName = "[email protected]";  
  6.         string password = "@#$%^";  
  7.         log.Info("C# HTTP trigger function processed a request.");  
  8.         // parse query parameter  
  9.         string listName = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "listName"true) == 0).Value;  
  10.         string description = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "description"true) == 0).Value;  
  11.         string requestlistName = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "requestlistName"true) == 0).Value;  
  12.         string requestid = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "requestid"true) == 0).Value;  
  13.         // Get request body  
  14.         dynamic data = await req.Content.ReadAsAsync < object > ();  
  15.         // Set name to query string or body data  
  16.         listName = listName ? ? data ? .name.listName;  
  17.         description = description ? ? data ? .name.description;  
  18.         requestlistName = requestlistName ? ? data ? .name.requestlistName;  
  19.         requestid = requestid ? ? data ? .name.requestid;  
  20.         System.Security.SecureString secureString = new System.Security.SecureString();  
  21.         foreach(char ch in password) {  
  22.             secureString.AppendChar(ch);  
  23.         }  
  24.         SharePointOnlineCredentials creds = new SharePointOnlineCredentials(userName, secureString);  
  25.         using(var ctx = new ClientContext(siteURL)) {  
  26.             ctx.Credentials = creds;  
  27.             ListCreationInformation creationInfo = new ListCreationInformation();  
  28.             creationInfo.Title = listName;  
  29.             creationInfo.Description = description;  
  30.             creationInfo.TemplateType = (int) ListTemplateType.GenericList;  
  31.             List newList = ctx.Web.Lists.Add(creationInfo);  
  32.             ctx.Load(newList);  
  33.             ctx.ExecuteQuery();  
  34.             UpdateListStatus(siteURL, requestlistName, int.Parse(requestid), "Approved", ctx);  
  35.             return req.CreateResponse(HttpStatusCode.OK, "List created successfully. List Name: " + listName + " Description: " + description);  
  36.         }  
  37.         public static void UpdateListStatus(string siteUrl, string ListName, int itemid, string status, ClientContext clientContext) {  
  38.             List oList = clientContext.Web.Lists.GetByTitle(ListName);  
  39.             ListItem oListItem = oList.GetItemById(itemid);  
  40.             oListItem["Status"] = status;  
  41.             oListItem.Update();  
  42.             clientContext.ExecuteQuery();  
  43.         }  

After publishing the above-mentioned Azure function, you will get the following URL:

https://xxxx.azurewebsites.net/api/CreateList?code=<GUID>&listName=Test18April1&requestlistName=ListCreationRequest&requestid=10

A similar function can also be created to Reject the request.

Step 5

Compose the actionable message. Please make sure to change the:

  • Originator – which would be the provider id mentioned above.
  • Post URL – Azure Function Post URL to call the SharePoint operation.

In the following message, I have designed two main actions from the admin:

  1. Create List and approve the request by clicking on “Create List” button.
  2. Reject Request – Rejects the list creation request and updates the system. In the current sample, I have not included the code as that would be similar to CreateList Azure function (above mentioned)

  1. <script type="application/ld+json">  
  2.     {  
  3.         "@context""http://schema.org/extensions",  
  4.         "@type""MessageCard",  
  5.         "originator""<Originator ID>",  
  6.         "hideOriginalBody""true",  
  7.         "themeColor""00C85A",  
  8.         "sections": [{  
  9.             "title""Please select the option to perform the action",  
  10.             "text""Click **Learn More** to learn more about Actionable Messages!"  
  11.         }],  
  12.         "potentialAction": [{  
  13.             "@type""ActionCard",  
  14.             "name""Perform Action against request",  
  15.             "inputs": [{  
  16.                 "@type""TextInput",  
  17.                 "id""feedback",  
  18.                 "isMultiline"true,  
  19.                 "title""Approved"  
  20.             }],  
  21.             "actions": [{  
  22.                 "@type""HttpPOST",  
  23.                 "name""Create List",  
  24.                 "isPrimary"true,  
  25.                 "target""varPostURL×" [This is a variable defined in flow which containing the AzureFunction Post URL]  
  26.             }, {  
  27.                 "@type""HttpPOST",  
  28.                 "name""Reject Request",  
  29.                 "isPrimary"true,  
  30.                 "target""http://"  
  31.             }]  
  32.         }, {  
  33.             "@type""OpenUri",  
  34.             "name""Learn More",  
  35.             "targets": [{  
  36.                 "os""default",  
  37.                 "uri""https://docs.microsoft.com/en-us/outlook/actionable-messages"  
  38.             }]  
  39.         }]  
  40.     }  
  41. </script>  
  42. <p> Please perform the action using e-mail </p>  
Step 6

Create O365 flow on the new item created event on the “ListCreationRequest” list.

 

 SharePoint

Step 7

Define a variable in the flow to hold the post url. Here ListName & ID are the dynamic values which are fetched from the “ListCreationRequest" list when a new item is created.

 SharePoint

Step 8

Define a Compose variable to hold the Actionable message body

 SharePoint

Step 9

Pass the Compose variable as an e-mail body

 SharePoint

Step 10

Send the e-mail to site collection admin/approver to perform the action against it using Flow. Please use “isHTML” option to send the actionable messages.

 SharePoint

Step 11

Verification of the action; i.e., whether List is created or not. Status is updated in the “ListCreationRequest” list against the requested id.

You can verify the steps by doing the following actions:

  1. Make a new request in the “ListCreationRequest” list to mimic the behavior user is raising a request to create a list under the defined site collection.
  2. After making a request in the list, site collection admin will get an e-mail to perform the action.
  3. According to the action taken by admin, you can verify the list & whether the request status is provisioned or not.

The above mentioned three steps are enough for a successful validation.

You can enhance the use case by putting extra components in the flow and an actionable message upon the action performed by the site collection admin; the requestor will receive the notification about approval/rejection of the request etc.

Please provide your valuable comments about this article.

Happy Coding!!