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,
- Send message via Graph APU and Console Application - Send Actionable Message via the Microsoft Graph
- Send message using SMTP service and Python script - Send Actionable Message via SMTP
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

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

Step 4
Create an Azure function and publish to the Azure environment.
- using System.Net;
- using Microsoft.SharePoint.Client;
- public static async Task < HttpResponseMessage > Run(HttpRequestMessage req, TraceWriter log) {
- string siteURL = "https://xxxxxxx";
- string userName = "[email protected]";
- string password = "@#$%^";
- log.Info("C# HTTP trigger function processed a request.");
- // parse query parameter
- string listName = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "listName", true) == 0).Value;
- string description = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "description", true) == 0).Value;
- string requestlistName = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "requestlistName", true) == 0).Value;
- string requestid = req.GetQueryNameValuePairs().FirstOrDefault(q => string.Compare(q.Key, "requestid", true) == 0).Value;
- // Get request body
- dynamic data = await req.Content.ReadAsAsync < object > ();
- // Set name to query string or body data
- listName = listName ? ? data ? .name.listName;
- description = description ? ? data ? .name.description;
- requestlistName = requestlistName ? ? data ? .name.requestlistName;
- requestid = requestid ? ? data ? .name.requestid;
- System.Security.SecureString secureString = new System.Security.SecureString();
- foreach(char ch in password) {
- secureString.AppendChar(ch);
- }
- SharePointOnlineCredentials creds = new SharePointOnlineCredentials(userName, secureString);
- using(var ctx = new ClientContext(siteURL)) {
- ctx.Credentials = creds;
- ListCreationInformation creationInfo = new ListCreationInformation();
- creationInfo.Title = listName;
- creationInfo.Description = description;
- creationInfo.TemplateType = (int) ListTemplateType.GenericList;
- List newList = ctx.Web.Lists.Add(creationInfo);
- ctx.Load(newList);
- ctx.ExecuteQuery();
- UpdateListStatus(siteURL, requestlistName, int.Parse(requestid), "Approved", ctx);
- return req.CreateResponse(HttpStatusCode.OK, "List created successfully. List Name: " + listName + " Description: " + description);
- }
- public static void UpdateListStatus(string siteUrl, string ListName, int itemid, string status, ClientContext clientContext) {
- List oList = clientContext.Web.Lists.GetByTitle(ListName);
- ListItem oListItem = oList.GetItemById(itemid);
- oListItem["Status"] = status;
- oListItem.Update();
- clientContext.ExecuteQuery();
- }





Join the conversation! Your thoughts help the community grow.