Workflows and SharePoint External Users
This article is about SharePoint Designer 2013 workflows, and SharePoint Online (Office 365) external users.
In building a solution for a customer, where there’s a SharePoint site / O365 Group with external users, and tasks needing to be assigned to them, this is the problem I noticed. When you invite an external user to SharePoint, they receive an invitation email. If they do not click the link in the actual invitation email, they will not gain access to the site. In other words, even after they’ve been invited, if they try to just navigate to the site directly, or click a link in any other email to take them to the site, they will get access denied, an error saying that you don’t exist in the directory yet. In this solution I’m building, the external users that will be invited to each site, will have tasks assigned to them, to review and approve documents around a certain project. After I’ve invited an external user to the site, I can assign tasks to them, the people picker will let me put their name in the Assigned To box. Also, workflow emails will successfully go to this person, and even alerts and those automatic task assignment emails. BUT, and here’s the problem, if that person hasn’t accepted the sharing invitation yet, and they click links in any other emails, they will not be able to access the site. THIS COULD GET REALLY CONFUSING.
7/21/2017 Update: In Office 365 admin, you do have the ability to change a global setting, to turn off the requirement for users to have to accept the invitation before they can access SharePoint. Go to SharePoint Admin -> Sharing. In the Notifications section, uncheck this box, External users accept invitations to access files
Of course, not all of you have access to global admin, and not all of you would be allowed to turn this setting off, because it does impact sharing in your whole tenant. So, keep reading if you’re not going to uncheck this box.
So, I pondered, how in the world will my workflow know if that user is not only external or not, but whether they have accepted the sharing invitation? I want to be able to do something different in my workflow under the condition of whether that has happened yet. I noticed that there is a condition called “Person is a valid SharePoint user”, but that did not give me what I needed.
This is pretty advanced, using a web service call, but here’s how I did it:
Here’s’ what I already have in place. In my workflow, I’m using the Create List Item action, to create a task, and I’m putting the user it’s assigned to, in the Assigned To field. I’ll need that variable that it returns to me, the GUID of that specific task. Note that I’m not providing you with any kind of full approval solution, this is just the part where you determine if a user is not only external, but has accepted the invitation. Another thing you’ll need to have in place, is a people-picker field already populated with that user who you want to send the email to. We’ll be extracting the information about that person, using the value in that field. This particular workflow is running from a document library, creating items in a task list, but you could run the workflow from the task list itself if you’d like.
In my workflow, after the task has been assigned, here’s what needs to happen. This is the high level screenshot, and then I’ll break it down.
- Build a dictionary. Click the blue word this, and your dictionary is going to have 2 items in it:
The Build a dictionary item will then look like this. Click OK.
- Build a dictionary. Click the blue word this, and your dictionary is going to have 2 items in it:
- The next action to add is Call HTTP Web Service. Click the first this, and put this in it:
YOURSHAREPOINTSITEURL/_vti_bin/client.svc/web/lists/getbytitle(‘Tasks’)/items?$select=ID,Title,AssignedTo/Name,AssignedTo/Title,AssignedTo/EMail,AssignedTo/UserName&$expand=AssignedTo&$filter=(GUID eq ‘VARIABLEOFTASKGUID’)
Mine looks like this:
In this step, here’s what is happening. I’m getting a list called Tasks, and the only fields I need in my case, are the ID, Title, and who it is assigned to. As you can see, since Assigned To is a people field, it is more complicated. For that person that I’m retrieving, I’m getting these fields: Name, Title, EMail, and UserName. THESE ARE ALL CASE SENSITIVE. Then, in the filter part of this request, I’m saying that I only want to retrieve that one task, the task I just created, and I’m using the Create variable (which is a GUID) in order to narrow it down to that one. Like I mentioned, I’m running this workflow from a document library, and it’s creating items in the task list. BUT, if your workflow is running on the task list itself, you’d still need to do the web service call, your filter would just be slightly different. It would be $filter=(ID eq ‘[currentItemID]’) <- that part in red is where you’d actually use the picker to select the ID field of the current item.After you’ve added your web service action, you’ll need to right-click on that row, and choose Properties. Notice that I’ve renamed a couple of my variables, that part is up to you. The important step that you have to do, is in RequestHeaders, you have to select your dictionary variable from step 1. Click OK.
Also, for troubleshooting purposes, I like to send myself an email Send an Email in the workflow, with the JSONtask variable inserted into the body of the email. That way I can see exactly what is returned. You can do that anywhere after step 2.
- Add the Get an Item from a Dictionary action (there will be five of these). Click on the blue item by name or path, and just type the following: d/results
Look at the screenshot above step 1, at 3, and see that for the dictionary selection, I selected the name of the same one (JSONtask) that is being generated in the call web service action above it. Notice that I renamed the output variable to TaskDataset (a dictionary variable)
- Add a second Get an Item from a Dictionary action. Click on the blue item by name or path, and just type the following: (0)/AssignedTo/UserName
From Variable: TaskDataset, output to TaskUserName (string).
- Add a third Get an Item from a Dictionary action. Click on the blue item by name or path, and type the following: (0)/AssignedTo/Title
From Variable: TaskDataset, output to TaskUserTitle (string).
- Add a fourth Get an Item from a Dictionary action. Click on the blue item by name or path, and type the following: (0)/AssignedTo/EMail
From Variable: TaskDataset, output to AssignedEmail (string).
- Then, if we want to be able to put a link to the task in the email, and the workflow is running on a list other than the task list, we’ll need to obtain the ID of the task item. Add a fifth Get an Item from a Dictionary action. Click on the blue item by name or path, and type the following: (0)/ID
From Variable: TaskDataset, output to TaskID (string).
- Steps 8 and 9. If the UserName variable is empty, then that means that the external user has not accepted their external sharing invitation yet. So, this is the way that you’ll be able to do something different for those people. If UserName is not null, of course, then I can send them an email with a link to the document, to the task, to SharePoint, or anything at all. If UserName IS null, then I most likely don’t want to send that person any hyperlinks to SharePoint. Maybe you could send the project manager an email, letting them know that xyz person has a task assigned to them, but hasn’t accepted their sharing invitation yet. Or maybe you could send the assignee an email that just has text and no hyperlinks, letting them know that they’ll have to go find that sharing invitation email and click on the link in it before they’ll be able to get to their assigned task.
Also, this isn’t something that I included in the actual workflow screenshot, but if you wanted to, you could put together different conditions or different email verbiage for external users versus internal users. The condition for that would be: If TaskUserTitle contains @
Why did I create a TaskID variable? What’s the purpose of it. When I’m assigning tasks to people, I like to take them straight to the edit form of the task, so that it’s one less click for them. That URL is YOURSITE/lists/YourTaskList/editform.aspx?ID=TaskID
To figure out all of this with the $expand of the people field to get more into, Marc Anderson’s post was helpful: Moving from SPServices to REST, Part 4: Converting GetListItems to REST. Scroll down to the very last couple of paragraphs, where he shows how to expand the AssignedTo field. The most important part to remember, is that this is very unforgiving. It is case sensitive, and be sure not to leave out any single quotes, either. Here’s another good link. Also, MSDN has a great, very thorough reference on how to use this web service syntax.
Here’s what I discovered. Back in step 2 when I mentioned about putting an email action in the workflow to send me the results, well that’s how I figured out how to tell the difference between the external users and internal users, and the external users who haven’t accepted an invitation yet. You can ignore the second “Title” field here in the output, that’s the actual title of the task. Remember, I’m not a dev. I’m just noticing a pattern here. The first pattern that I noticed, is that when the user is an external user, the user’s Title field is an email address.
I also noticed, and this is the main crux of this article, that when the UserName field is null, that indicates that it’s an external user who has NOT accepted the sharing invitation yet. That is why we use the logic in step 8.
Here’s another reference. If you’re interested in learning more about using web services with workflows, here’s my SharePoint Power Hour episode on that topic. This is my non-dev way of explaining how I understand and use it.
Hi Laura, Thanks for this guide.. I have a similar problem to solve for a customer and we have disabled the checkbox as you mentioned. I am getting an approval mail on the external party but whenever he/she approves we get an error saying that The remote endpoint returned an error HTTP forbidden. Am i missing something? What i have build is a SharePoint modern list with content approval on that list. Then i build a Power app from that list so that people can submit their working hours. The person that must approve is from external origin. After this i build a flow from the custom list that is derived from the standard approval workflow template when a new item is created. I modified the last steps to have the list item approved or reject.