There is probably only one thing more important in today’s business marketplace than approving content and that is the creation of the content itself. The introduction of the Approvals actions in Microsoft Flow has changed the process for creating approval workflows in many ways. Gone are the days when content had to be inside SharePoint or OneDrive to use an approval workflow. With 100’s of connectors, we can now create approvals for content stored in almost any system. Flow Approvals have also simplified the process. The process is now as simple as:
- Creating a Flow using a content specific Trigger
- Adding an Approvals action to the Flow
- Selecting the approval type
- Approval by one person or everyone
- Reject/Approve or custom responses
- Filling in the details for the approval
Then just wait for the approval responses. Sending parallel approvals is built into the action. Sending approvals serially is as easy as using multiple approval actions one after another.
It’s all easy and straight forward right? Wrong, because as soon as you get used to the power of the approval action you start running into situations where you want to change some aspect of how it works. This eBook will walk you through seven (7) typical issues that people run into using the approval action. I’ll also show you simple workarounds for how to solve those issues. Using the techniques in this eBook will help you take your approval workflows to the next level.
The first issue that most people face when working with approvals is how to format the request message that goes to the person who will be approving the content. Unlike the Send an Email V2 action, the Approval action doesn’t provide a What you see is what you get (WYSIWYG) editor toolbar like the one in the screenshot below. You can’t manually embed Hypertext Markup Language (HTML) codes either. The editor appears to be a simple text box.
But the lack of WYSIWYG and HTML doesn’t mean that we must merely live with plain text messages. If you look closely in the Details input box in the approvals dialog you will see a hint that markdown codes are available. And if you visit the website at https://aka.ms/approvaldetails you will find a limited set of codes that you can use to transform your plain text message into something with a bit more formatting.
The markdown codes provide support for the following:
- Headers – Format a line of text like an HTML <H1> to <H5> tag
- Paragraphs and line breaks – Put white space between paragraphs to make them more readable
- Lists – Create bullet or numbered lists that can contain multiple levels
- Links – Add URL or Anchor tag (tied to headers) hyperlinks
- Tables – Display content in a table with column alignment
- Emphasis – Apply bold, italics, or strikethrough formatting to text
- Special Characters – Use escape codes for special characters
The screenshot below shows an example of an approval message formatted using the markdown codes. Note that you can also insert fields from other actions into the flow as dynamic content. The result is a custom formatted message that presents information to the approver in the best way.
One final note should be made. Some of the formatting codes won’t work on all browsers or email clients. This is particularly true of the paragraph and line break codes.
The next challenge we run into using approvals with SharePoint is that the results of the approval aren’t recorded in the list or library. They are maintained in the Flow approvals history tab. But this history tab is only available to the owners of the Flow and you must look at an individual run to get comments and the outcome of that approval. Furthermore, the history list is only searchable by the Flow title. So how do I find one approver’s comments after thousands of approval runs all with the same title?
With just a little pre-planning we can store the outcome of the approval and any comments that were made right in the metadata of the list item or document. And if you enable Require Approvals in the list/library we can even use the outcome to set a standard approval mechanism in SharePoint. To prepare our list or library for storing the results of the approval we need to do a couple of things:
- Add a column of type Multiple lines of text or the predefined Comments site column
- Enable Require content approval for submitted items In the versioning settings or create a column called ‘Sign-off status’ of type Single line of text
Once those two columns are in place, we are ready to start building our approval Flow. It starts like any other approval Flow. But in this Flow, we initialize a variable of type string. This will provide a place to aggregate comments if we have more than one approver. You can see the Initialize Variable step in the screenshot below.
Next, we add actions after the approval action in the Flow to process and record the results of the approval. Since we could have more than one response if we had multiple approvers, any response returned by the approval action will come in the form of a set of records. This is true even if there is only one response. When we try to append the approver’s name and comments returned with the approval results to the string variable we created earlier, Flow will automatically put this action inside an Apply to each loop. This will work whether we have zero (0), one (1), or any number of responses. Make sure you add a carriage return before you add the approver’s name and comments fields. Otherwise, the responses will all be jumbled together and difficult to read. You can see the resulting loop in the screenshot below:
Once the comments have all been added to the variable, we can move on to update the SharePoint list item or document that was being approved. You can do that with a SharePoint Update file properties action. The action knows which item to update based on the Id field that was included in the trigger that started the Flow. Simply add the Outcome of the approval and the Approval Comments variable to the fields you added to the list/library for recording the results.
You can also use a separate Set Content Approval status to update the standard content approval for the item. There is an extra step required to do that if you are approving a document. To avoid update conflicts in the document metadata you need to supply the ETag. The ETag is a special identifier that identifies the specific version of the document that is pending approval. You can retrieve the Etag for the document you are approving using the Get file metadata action, by specifying the document’s unique identifier This was one of the properties in the trigger for the Flow. Then just fill out the Set Content approval status action as you see in the screenshot below.
When you are all done your approval status and the comments made by all the approvers will be clearly visible right in the document library for anyone who has access.
Tip #3 – Creating custom responses without premium licensing
Not all approvals are as simple as Approve/Reject. Sometimes there are more than two options. Maybe we are taking a vote on whether something should be approved or not and want to provide the option to abstain. Or we might want to gather some specific information, other than comments, in response to an approval. The Approvals V2 actions introduced the ability to replace the typical Approve/Reject choices with any number of user-defined choices. But using actions like Start and wait for approval V2 with custom responses requires a premium P1 or better license so it may not be available in your organization. If your users have premium licenses, then I recommend you continue to use the regular approval actions. But if you don’t have premium licensing there is another way.
Before the approvals actions became available in Flow most people created approval Flows using the Send approval email action. This action was renamed Send Email with Options after the approvals actions were released. But it is still available. It doesn’t have all the features available in the new approvals action, like integration with the mobile client or appearing on the Approvals tab in Flow. But it does let users specify their own comma-delimited list of approval responses and it is still under standard licensing.
Creating an approval using the Send email with options action is as easy as filling out the dialog form displayed in the screenshot below. Most of the fields are identical to the ones available in the regular Send an Email v2 action. We just fill them in and insert dynamic content from the Flow where appropriate. But there are a few fields highlighted in the screenshot below that require further explanation.
These highlighted fields are either not available in the standard Send Email v2 action or they are not widely understood and require additional explanation.
- User Options – This field holds the options that are presented to the approver as buttons in the email. Clicking on one of these options will return that value to the Flow.
- Selection Text – This is the label that will be displayed just above the buttons at the bottom of the email.
- Use only HTML message – Setting this to Yes will allow the use of HTML formatting tags in the Body of the email. This is important since the markdown characters available in the regular approval action don’t work here.
The screenshot below highlights where the selected text and the Options buttons are in the email. You can also see the results of the HTML formatting in the message.
When a user clicks on one of the options presented in the email, the text of that option is returned to the Flow. We can then use a Switch action to implement the steps that should be taken for each option. In the screenshots below, we use the SelectedOption to determine how to update the item being approved. One limitation on the Send email with options action is that it can only return the selected option. There is no way to capture any user comments like there is with the normal approvals actions.
Tip #4 – Forwarding an approval if the approver is out of the offce
Approvals only work if the approver sees the request and acts on it. But what if the person who normally approves content is out of the office for a few days or weeks? Can you afford to wait until they come back? Do you expect them to work while their out and approve content even if they are on vacation?
In these situations, we would like to be able to determine that the intended approver is out of the office and forward the approval to someone else instead. One way to check if an approver is out of the office is to query their mailbox to see if they have set their “Out of Office” message. We can do that using the Get mail tips for a mailbox action. The only parameter for the action is the email address of the person who might be out. The return value from this action is the actual “Out of Office” message, so if we get a null message in the return then we can assume the approver is not out. You can see in the screenshot below where we retrieve the message and check to see if it is null or not. We also initialize two variables that will be used to determine who to forward the email to if the original approver is out.
If the Message is null then we go down the yes side of the Condition and send the approval normally. But if the “Out of Office” Message is returned then we process the no side of the Condition. This is where those two variables we initialized above come in.
When people set them “Out of Office” message it is customary to include the email of the person who is handling things for them while they are out. We are going to extract that email as the person we should forward the approval to. To do this requires three (3) steps:
Search for the location of the first ‘@’ sign in the Message. This should be the middle of the email address we want. Store that in the atSign variable. Here’s the formula used to do that:
Split the first half of the Message, up to the location of the ‘@’ into an array of words. Select the last word. This is the beginning of the user’s email. Store that in the username variable.
Split the second half of the Message, everything following the ‘@’, into an array of words and append the first word, including the ‘@’ sign, onto the username variable.
The username variable now contains the email address of the contact person. Of course, there is a lot more error checking we should do to make sure there is one and only one email address in the message but that is beyond the scope of this example. Once we have the email we send the approval to them using the normal approvals action.
It should be noted that this solution depends on several assumptions.
- The approver has set their “Out of Offce” message when they are unavailable.
- The OOO message includes at least one email address suitable to be used to forward approvals
- The OOO message doesn’t include multiple email addresses
Appropriate logic and error checking should be added to the basic pattern to adjust when these assumptions are not met. Governance policies should also be put in place to ensure that people set their “Out of Offce” message when they will be unavailable for an extended length of time.
Even if you get the request to the right approver, what if they don’t respond in a timely fashion? How can we set a deadline and escalate the approval to someone else if the original approver doesn’t respond within the allotted time? The screenshot below is a high-level summary view of an approval that will automatically escalate to another user if the first one doesn’t respond in time. We do that by adding a parallel branch to do the escalation that only runs if the approval response doesn’t arrive within a pre-defined time. If the approver does respond, then the other branch completes the approval normally. Finally, we come back together after the parallel branches to complete the Flow by recording the outcome in SharePoint as demonstrated in Tip #2.
To escalate the approval, we’ll make use of some of the settings built into the Approval workflow and the error handling functionality available in Flow. The first step is to access the Settings on the Wait for Approval to Manager action by clicking the ellipse, the ‘…’, on the right side of the action title bar. In the Settings dialog we can set the Timeout Duration for the action. This controls how long the Flow will wait for the approval response before moving on to the next action in the Flow.
The timeout duration is encoded using a standard pattern called ISO 8601. The encoding pattern looks like this, P(n)Y(n)M(n)DT(n)H(n)M(n)S, where (n) is replaced by the number of days, hours, or minutes. Here’s an outline that will explain the different characters in the pattern. P7D in this example would timeout waiting for the approval after 7 days.
- P is the duration designator (referred to as “period”) and is required
- Y is the year designator that follows the value for the number of years
- M is the month designator that follows the value for the number of months
- W is the week designator that follows the value for the number of weeks
- D is the day designator that follows the value for the number of days
- T is the time designator that precedes the time components and is required
- H is the hour designator that follows the value for the number of hours
- M is the minute designator that follows the value for the number of minutes
- S is the second designator that follows the value for the number of seconds
Now that we’ve set the approval to timeout after 7 days, we need to configure one of the parallel branches to run if the approval times out. This is where the error handling takes over. In the same menu where we accessed Settings, there is another link called Configure run after. The screenshot below shows that actions can be set to run when the previous action ran successfully (the default), failed, was skipped, or timed out. We’ll set the scope in our escalation branch to run if the approval times out. You can check the Configure run after settings in the scope of the other branch too, but it should already be set to is successful, which is what we want.
Now let’s take a look at the escalation branch that will run if the approval times out. The first action in this branch is the use the Common Data Service (CDS) to delete the approval that timed out. It should be noted that this is a premium feature, but it is the only way to remove the pending approval from the Flow Approvals tab and mobile client. There is currently no way to remove the email that was sent to the user. The rest of the escalation branch is just like any other approval Flow. We get the manager of the original approver, send out a new approval, and when they respond we store the outcome and comments in string variables that we can use later to update SharePoint. You can see the full escalation branch in the screenshot below.
If the approval doesn’t time out, then we go through the other side of the parallel branch. The actions here are to simply store the outcome and comments in the same variables that we would use if the approval timed out.
Once the parallel branch completes, we come back together and complete the flow by recording the outcome and comments in SharePoint. We also must set the Configure run after settings for this action to run if the branch was successful or skipped. If the approval times out, then the non-escalation branch will be skipped and the escalation branch will be successful. If the approval doesn’t time out, then only the non-escalation branch will run. If we don’t configure the last action to run whether the branches are skipped or successful, then it will throw an error after the non-escalation branch completes.
Tip #6 – Sending periodic reminders about pending approvals
Approval completion isn’t always delayed just because the approver is “Out of Offce”. Sometimes people just get too busy with other things and forget to respond. In these instances, a timely reminder may be all that is needed.
The screenshot below shows a high-level diagram of a Flow that uses a parallel branch to send periodic emails while the other branch waits for the approval response. In Tip #5 we used special settings to select which branch would run. In this Flow we want both branches to run at the same time so we can send reminder emails while we are waiting for the approval response to be returned.
The branch that handles the looping reminder is pictured in the screenshot below. We start a Do until loop that will continue to run until we tell it to stop by changing a Loop control variable that we established called StopReminders to True. You can see in the screenshot above where we initialized the variable to False before sending out the original approval.
Once in the reminder loop, we wait for 7 days and then send an email reminder to complete the Approval. We include a link to the approval item and the approval request in the reminder email to make it easier for the approver to complete their task. The loop will continue to send out reminders every 7 days until the StopReminders variable is set to true.
The approval side of the parallel branch has just two actions in it. The first is to wait for the approval response to return. When it does, we set the StopReminders variable to True to tell the other branch to stop the loop that sends reminders. This will stop the loop the next time it cycles and exit the branch, finishing the Flow.
Two potential issues should also be mentioned. Since the loop is evaluated at the top of the loop there will always be one last email reminder after the approval is responded to. One potential enhancement that should be considered is to add conditional logic to the reminder email action so it is not sent if the StopReminders variable has been set to True.
Another concern is how to handle reminders for multiple approvers? Are reminders sent to all approvers even if some have already responded? Or should another variable be added that will be used to populate the To field in the reminder so the approver’s email can be removed after they respond?
Both of these would be good enhancements but are beyond the scope of this example.
Tip #7 – Building an approval workflow for an adjustable list of approvers
All our examples so far have been designed with the assumption that there was only one approver. But sometimes you need to get approval from a whole group of people. If we know beforehand how many approvers there will be, we can easily adapt typical serial and parallel approval designs for any number of approvers. But what if we need approvals from an unknown number of people. How can we design a serial approval process that will send the approval to each person in turn until either everyone approves, or one person rejects the approval request? The screenshot below shows a high-level diagram of an approval Flow designed to implement this kind of logic.
In this example, the approvers are added to a Person/Group column in the SharePoint list item that supports selecting multiple people. After initializing a variable to hold a summary of approver responses (see Tip #2) and a variable to hold whether anyone has rejected the approval we start an Apply to each loop that will process each approver in the Approvers field in SharePoint. At the top of the loop, we check to see if anyone has previously rejected the request. If not, we send an approval request to that user and wait for a response. When the response arrives, we append the responses to a variable and check to see if the approval response was a rejection. If it was, we change the Rejected variable to True. If Rejected equals True then the next loop will simply fall through and do nothing, so no further approval requests will be sent.
There you have it. Seven examples of how to take your approval Flows to the next level. Are these the only workarounds you will ever need when it comes to approval Flows? Probably not, but these should help you start thinking out of the box and taking another look at all the capabilities available in Microsoft Flow. Who knows, you may be the one who comes up with the next great workaround that solves someone else’s problems. I hope these seven solve a lot of yours.