We have been waiting for To Do API's in Microsoft Graph for ages, it seems, and they finally made it into the /beta endpoint (announcement / overview / how-to). From everything that was hinted/known before, I assumed they would initially be just a 1-to-1 replacement of the Outlook Tasks API's. While listening to the Microsoft 365 Developer Podcast episodes around these new API's, I learned there is at least one new thing included too: Linked Resources.

Linked Resources are explained as a connection to the source application of the task, with a bit of contextual information and a direct link to the item that relates to this task.
Currently, this feature is only available through API, so I was wondering how this looks in the UI when a Linked Resources is associated to a task and how easy it is to use.

Use case

Besides the To Do API's, there was also another new thing I wanted to try: the "For a Selected Message" trigger in Power Automate. This was my opportunity to combine all of them, and create something actually useful:

  • Trigger a Power Automate flow on a specific message in Microsoft Teams
  • Create a Task in To Do for this specific message
  • Link from the Task in To Do back to the message in Microsoft Teams

Of course, this isn't a completely new idea: Vesa Nopanen has a nice blog post that shows this, but he puts the link to the Teams message in the body of the task. Same goes for Daniel Anderson who has a video showing this functionality. I'd like to use the Linked Resources feature, just because I can now 😊.

Power Automate flow

Power Automate doesn't (yet?) have actions for the new To Do API's, the existing actions point to the old Outlook Tasks API's and they don't surface the Linked Resources feature. As a result, I'll be using the "HTTP with Azure AD" premium action. This means that you'd need the correct licenses to reproduce it.

"For a selected message"-trigger

We'll create a new flow in Power Automate, and use the Microsoft Teams - For a selected message trigger. This will make the flow show up in the overflow menu on a Teams message, showing the title of your flow. It is thus best to choose a short but descriptive title.

This trigger allows you to use an Adaptive Card to ask more input. In this specific case, I opted not to and just let the flow trigger directly.

Initialize Task Subject

Your task in To Do needs a subject, and ideally all the messages in Teams have a subject set that you can use here. Now reality is that this isn't true. So when there is no Message Subject available, you should fall back to something else. I chose to use the first 80 characters of the message with some elaborate expression. This was also proving problematic, since the substring function fails when you want to get more characters then there are in the message so I had to introduce a min function to get 80 or the length of the message body if it is smaller than 80:

if(empty(triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['subject']), substring(triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['body']?['plainText'], 0, min(80, length(triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['body']?['plainText']))), triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['subject'])

Create the Task in To Do

Last step is now to create an actual Task in To Do. I use the HTTP with Azure AD action, because it alleviates the hassle of fetching an access token to call Microsoft Graph API's. When using this for the first time, it asks for a Base Resource Url and Azure AD Resource URI (Application ID URI). Just enter https://graph.microsoft.com in both boxes:

I'll be using just the Create task action from the Microsoft Graph API's, which in essence expects a POST call to a specific endpoint:

POST /me/todo/lists/{todoTaskListId}/tasks

I want to create these tasks in the default Tasks list, that exists in every To Do instance. At first, it looked like I needed to fetch the ID of that list through some additional call to List all TaskLists, using some filters.
Task Lists return with a property called wellknownListName and as a value the default Tasks list has defaultList. I tried a $filter expression on it

GET https://graph.microsoft.com/beta/me/todo/lists?$filter=wellknownListName eq 'defaultList'

but it failed with an ugly response:

{
    "error": {
        "code": "generalException",
        "message": "Internal Server Error",
        "innerError": {
            "date": "2020-08-24T21:22:01",
            "request-id": "45a075b7-9738-4218-857a-6ca6c679e638"
        }
    }
}

It seems this endpoint does support $filter on displayName, so that might help in some cases too. While trying out all this stuff, on a whim, I tried using just Tasks as the id value instead of the actual ID:

GET https://graph.microsoft.com/beta/me/todo/lists/Tasks 

IT WORKS!

Just be cautious: this is documented nowhere and I just found it by accident, this may stop working at any time (given /beta endpoint and undocumented). I am not sure how this behaves with To Do in different languages: do you still use Tasks even when your default list has a localized name? I'm not sure...
I also tried some other list names, but it seems only Tasks has this behaviour.

Continuing with the flow, I now only need one action:

POST https://graph.microsoft.com/beta/me/todo/lists/Tasks/tasks 

and provide it with a message body that will create the Task in To Do:

{
    "title":"Task from Teams: @{variables('TaskSubject')}",
    "body":{
        "content": "@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['body']?['plainText']}",
        "contentType": "text"
    },
    "linkedResources": [{
        "webUrl": "@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['linkToMessage']}",
        "applicationName": "Microsoft Teams",
        "displayName": "@{variables('TaskSubject')}",
		"externalId": "@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['id']}",
	}]
}

I give the Task a title (see previous section) and pass in the message content from Teams as the body of the Task. The create Task endpoint allows you to immediately create a Linked Resource in the same call (it also has separate CRUD operations available), so I provide:

  • webUrl: link to the message in Teams, this is retrieved from the "For a selected message" trigger.
  • applicationName: I chose "Microsoft Teams" because the message links back to Teams. You can pick whatever name you'd like, and it'll show in the To Do UI.
  • displayName: this is a name for the item in the external system, it'll also show in the To Do UI. I chose to use the TaskSubject again, since it represents the message in Teams.
  • externalId: an id to uniquely identify the item in the external system, I chose the id of the message in Teams on which the flow was triggered.

Complete flow in Power Automate

Microsoft Teams behavior

As shown above, the flow will show up on each message underneath the three dots and then the "more" menu item. Clicking on it will spawn a popup box, which would host the Adaptive Card if we had chosen to use it. In our case it just directly shows that it triggered the Power Automate flow successfully:

To Do behavior

If the flow runs correctly, I see my newly created task in the Tasks list in To Do. Now I can follow up on these messages in Teams by using To Do, where all other stuff I need to follow up on is located. In To Do, it'll look like this:

You can immediately see on a Task in the overview that it has a Linked Resource, in this case pointing somewhere in Microsoft Teams (it uses the applicationName property from above):

And in the details pane, it also shows the Linked Resource prominently while adding even more context information (the displayName property). You can also click it and it'll open the provided link (the webUrl property):

This showcases perfectly how To Do can now visualize tasks from other systems and still link back to the original location of the task, in the source application. I demonstrated it by using Microsoft Teams, but it's all free text so essentially any system can be used. It is a very flexible way of integrating other systems with the task management capabilities of Microsoft To Do!