Send and Receive Text Messages from Microsoft Flow

As the software development landscape matures, levels of abstraction keep getting higher. Every generation of technology raises the starting point a notch, enabling developers to create more and more interesting things while “boilerplate” or setup tasks become increasingly automated.

Nowadays, with tools like Flow and Azure Logic Apps, we can create some pretty cool integrated solutions without even having to write code.

Microsoft Flow is becoming a go-to no-code tool for authoring business process automations in the Microsoft ecosystem, replacing the old SharePoint Designer tool we all hated so much. In this blog post we’ll explore sending and receiving text messages via Microsoft Flow and integrating them into other systems to create fast, mobile-ready business applications.

What you’ll need

You’ll need a few things set up in order to follow along:

  • You’ll need an Office 365 license that includes Flow and Email
  • You’ll need a Twilio account. You can create a free trial account that includes a set amount of free credit to play around with. Twilio is a paid service, so you’ll need to pay for using it in real applications, but the free trial comes with (I think) $15 dollars worth of credit, and you can send and receive a couple thousand text messages with that amount, so you don’t have to commit to anything until you’re sure about the solution.

Building the solution

We’ll follow four steps to build out our sample Flow:
1. Create a shell HTTP-triggered Flow
2. Set up a webhook for incoming texts against our Twilio number
3. Send ourselves an email with the text content
4. Send ourselves a text message repeating the incoming message back to us

Create an HTTP-Triggered Flow

Go to Flow and create a new Flow with an HTTP trigger. Use the Create From Blank template and search using “HTTP” until you find the “When an HTTP request is received” trigger, and select it.

alt text

Our trigger will populate on the design surface. We won’t be able to see the trigger’s URL until after we save the Flow, and we don’t know what the post body schema is going to be, so we’ll leave that blank for now. Also, we need at least one action before we can save the Flow, so let’s just create a variable to hold the POST body of the trigger request. We’ll use it to generate our schema after we invoke our webhook for the first time. I used the Initialize Variable action, named the variable “Body”, set its data type as Object, and initialized it to the “Body” element from the trigger request.

alt text

Now give your Flow a name and save it. I named mine “Twilio Trigger” and note that once the Flow saves, the URL is populated in the action. Put this on your clipboard as we’ll use it in the next step.

alt text

Set up our Webhook

Once you’ve set up your Twilio trial account, you’ll need to create a SMS Project and a phone number. I do not find Twilio’s user interface easy to use, and I usually have to stumble around a bit before I can get anything done. But you’ll need to create a new project of type “Programmable SMS” and create a new phone number inside that project. To create a new number, go to https://www.twilio.com/console/phone-numbers/incoming and click the plus sign to obtain a new number. Once you have the number, go ahead and click it.

Note: for trial accounts, you will only be able to send and receive texts between your Twilio number and the phone you use to set up the trial.

Once you’ve clicked the number, look for the “Messaging” section and look for the “A message comes in” line. Paste your Flow URL into the text box and leave the defaults on the two dropdowns (“Webhook” and “Post”), and click Save.

alt text

Your webhook is now pointing to your new Flow. Send a text message to the Twilio number from the phone you used to set up your trial, and navigate to the Flow you built earlier. If you’ve done everything correctly, you should see one successful run of your Flow.

alt text

If you do not see any runs, then your webhook is misconfigured. If you see a run and it’s failed, then something has gone wrong with the Flow.

Complete the Flow

But assuming all went well, if you drill into the Flow run you can see the POST data sent to the Flow in the Body variable we set up.

alt text

Next we’ll copy that text and use it to generate our expected body schema for the HTTP Trigger. Put the Flow in edit mode, open up the HTTP trigger, click “Use sample payload to generate schema”, and paste in the text from the Body variable:

alt text

That body JSON looks something like this:

{
"$content-type": "application/x-www-form-urlencoded",
"$content": "VG9Db3VudHJ5PVVTJlRvU3RhdGU9REMmUU2MDlhN2EyM2IwOWQ4MjQxNmU4NTg3OCZBY2NvdW50U2lkPUFDOGNlOTQwOTM1ZDU5MDBjY2YxNzdmMDQzZjc4NDgyYWEmRnJvbT0lMkIxNTE3Mjk1OTgwNiZBcGlWZXJzaW9uPTIwMTAtMDQtMDE=",
"$formdata": [
{
"key": "ToCountry",
"value": "US"
},
{
"key": "ToState",
"value": "DC"
},
{
"key": "SmsMessageSid",
"value": "SM11d18181e323232323d82416e85234"
},
{
"key": "NumMedia",
"value": "0"
},
{
"key": "ToCity",
"value": ""
},
{
"key": "FromZip",
"value": ""
},
{
"key": "SmsSid",
"value": "SM11d18181e609a74244242416e85987"
},
{
"key": "FromState",
"value": "MI"
},
{
"key": "SmsStatus",
"value": "received"
},
{
"key": "FromCity",
"value": ""
},
{
"key": "Body",
"value": "Hello there"
},
{
"key": "FromCountry",
"value": "US"
},
{
"key": "To",
"value": "+12028738201"
},
{
"key": "ToZip",
"value": ""
},
{
"key": "NumSegments",
"value": "1"
},
{
"key": "MessageSid",
"value": "SM11d18181e21212121212416e85456"
},
{
"key": "AccountSid",
"value": "ACxxxxxxxxxxxxxxxxxxa"
},
{
"key": "From",
"value": "+15172953322"
},
{
"key": "ApiVersion",
"value": "2010-04-01"
}
]
}

Notice that all the data we care about – namely the sender and the message itself – are buried in an array of key-value pairs. To get at this data from our Flow, we need to loop through all the pairs and check until we find what we’re looking for. It’s not ideal but it’ll work. What we’ll do is loop through the keys, look for the one named “Body”, store the value of Body in a variable.

We’ll add a condition step, and inside the “choose a value” box we’ll select “key” from the Dynamic Content selector. When we do this, Flow will automatially wrap that condition inside an Apply To Each iterator. When “Key” is equal to “Body” we’ll store the value in a string variable, and then outside the loop we’ll email the text message to ourselves, completing the Flow.

Here are the actions to complete the Flow:

alt text

alt text

alt text

Testing

Now let’s send another text to the Twilio number. If all goes well, the Flow trigger again and light up green, and you’ll have the text content in your Email inbox.

Sending Text Messages

Sending a text message is much more straightforward. There is a standard Twilio connector in Flow, and you need to set up your initial connection parameters before fleshing out the action. To do this we need to grab our account SID and your auth token. You can get these from the Twilio dashboard at http://www.twilio.com/console

alt text

Setting up the Twilio connector

The first time you set up any Twilio integrations in Flow you’ll be prompted to flesh out your connector with the Account ID and auth token. Add a new action, search for “Twilio” and select the “Send Text Message” action.

alt text

If this is the first Twilio integration you’ve done on your tenant, Flow will prompt you to set up your connector. Give it a name and enter your Account ID and Auth Token from the Twilio portal.

alt text

After configuring the connection you’ll be able to fill out the action details. The ‘From’ phone number will be a dropdown list of all the phone numbers associated with the account. The ‘To’ number is a plain text number, but if you have a trial account you’ll only be able to successfully message the number linked to your account, and the text is also a plain text field. Of course you can use Flow dynamic data and functions inside these text fields.

alt text

Possibilities

Having the ability to interact with text messaging in Flow opens up a wide range of possibilities. Flow is a connection machine, and enables us to integrate with a wide array of services. Throw in some Azure functions and the power of Azure service offerings and we can implement anything we can imagine: AI-driven chat bots, reservation systems, bulk reminders and notifications, social media monitoring, critical IT systems monitoring, just to name a few off the top of my head.

Conclusion

We can easily create mobile-ready integrations with Microsoft Flow that can send and receive text messages. Receiving text messages involves a webhook and a bit of setup, and sending text messages is a simple action out of the box.

Advertisements

Emailing a SharePoint Group from Flow, part 2: The custom connector

In Part One of this blog I showed how email all users from a SharePoint group using Microsoft Flow. In part two I’ll show how to reuse this Flow from other Flows using a Custom Connector.

The “Email a SharePoint Group” Flow from part one is a standalone Flow that does one thing – emailing the SharePoint group. It’s invoked via an HTTP trigger, which means that to consume it from another Flow, you need to wire up a Request action with the appropriate URL and POST data. This isn’t ideal for two reasons: It requires knowing the arcane details of the endpoint and how to set it up in a Flow, and it necessitates exposing the endpoint URL to anyone needing to use it from a Flow.

In this blog we’ll abstract away the details of that action by wrapping it in a Custom Connector.

In other words, we’re going to go from this:

alt text

to this:

alt text

What you’ll need

In order to follow along you’ll need the following:
1. The Flow you created in Part One
2. Postman (you can download it here: https://www.getpostman.com/

Creating the Custom Connector

There are a couple different ways to generate a Custom Connector for Flow. We’ll use a Postman collection to help us generate the API definition that Flow needs to set up the connector.

We’ll use the following data as the inputs for our Postman collection. Remember, our Flow is onvoked via HTTP request to: https://prod-23.westus.logic.azure.com:443/workflows/0184591fa2bd4547b5ed01046cb51d18/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=qdPtgtY0Rn8vBAYNBLeISLh_I2s1etjWw7QrOZ_TO8Q

POST Body:

{
"siteUrl": "https://mytenant.sharepoint.com/sites/Home",
"groupName": "Home Members"
}

I won’t go into detail about how to create a Postman collection, (you can read about it here), but in a nutshell you’ll want to set up your POST request to your Flow URL and add the JSON to the body. Don’t forget to set the Content-Type to application/json, and choose to export a V1 collection version.

alt text

Once you’ve exported the collection, you’ll be ready to move into Flow and set up the custom connector.

Setting up the Custom Connector

In Flow, click the gear icon in the top bar and select “Custom Connectors”, then “Create Custom Connector” and select “Import a Postman Collection”.

Once the collection imports, you’ll see a four-step wizard where you’ll configure your connector.

In step 1, General, you have options to change the default color and logo. You can accept the defaults or set a custom look for the connector. We’ll stick with the defaults here.

alt text

In step 2, Authentication Type, leave the default at “No Authentication”

alt text

Step 3, Definition, is the most involved. Here you can tweak your actions and add new ones. We’ll have one action already defined, and you’ll see the four query string parameters passed into the POST request. We’ll want to hide these from the Flow author, so we’ll click on each one, select “Edit”, and set its visibility to “Internal”

alt text

alt text

Step 4, Test, will require we click the “Create Connector” button and actually consume the connector. We should see all our parameters, and if we add an appropriate POST body and click “Test Operation”, we should get a 202 response back. Also we should see that our souce Flow was triggered and ran successfully.

Create the Flow

Now we’re ready to create our Flow and consume the custom connector. Here I’ll just create a Button-triggered Flow and search my actions using the word “Email”. You’ll see I got two custom connectors back because I created two of them in my dev sandbox.

alt text

When you configure the action it’ll prompt you for a site url and a group name where the email will be sent. If I had set the visibility of the Content-Type parameter to “Hidden” that would have been gone from the interface as well.

alt text

Now you have a custom connector that you can re-use in all your flows to email any SharePoint group in any site your Flow author has access to. You also have a pattern for creating sub-Flows and a way to execute them in a scalable manner.

Homework

Try to create your own custom connector to email a SharePoint group. Pass the subject line and email body as parameters. Let me know how it went in the comments.

Copy Link in Modern SharePoint – non-obvious security implications you should know about

Recently I encountered a strange issue in a client’s Intranet during the content buildout phase. They’d given read-only access to a group of pilot users, and loaded up their site with pages and links to documents. Then they began to notice that these pilot users appeared to have the ability to delete the documents, and logged a bug with us.

We discovered that the document library had hundreds of files with broken permission inheritance, and that the Everyone principal had been granted Contribute permission on each one of these documents, meaning they could edit and even delete the documents.

Thinking that some rogue user had inadvertently (or “advertently”) shared those documents in error, we ran a script that looped through all the documents in each library and restored the permission inheritance on each one. Then we discovered that the several hundred or so hyperlinks to the documents throughout the system began returning 404s.

Eventually we tracked the issue down to a “feature” of the Copy Link action bar item in Modern SharePoint document libraries. We discovered that Copy Link does a bit more than merely return a link to the document to the user’s clipboard.

The Document Action Bar

My client had been using SharePoint’s Copy Link functionality to create those links, just as we had taught them to. But what we didn’t realize was that clicking Copy Link was actually breaking the security inheritance on the document, and sharing it to the entire company. This was because the tenant settings that drove this functionality were left in their default settings, which inexplicably default to the most permissive – the most insecure – setting.

Check out what happens when you click the button:

Copy Link Dialog

Once you see this dialog, permission inheritance has already been broken and the permission “Anyone with the link can edit” has already been applied. If you select another option, the permission will update – even to the point of reinstating permission inheritance if “People With Existing Access” is selected. Also, the link regenerates, and previously generated links become stale and return 404s.

Copy Link Options

The link structure will tell the sharing story

If a Copy Link operation results in broken inheritance, it will look different from a link that does not.

A Sharing Link looks like this:
https://m365x692092.sharepoint.com/:w:/g/Ea90HDWefS1BnLLgtVkMNJgBdpUI6LiBC7Kw4pj0g-CIAQ?e=troe2t

..while a non-shared link will look like this:
https://m365x692092.sharepoint.com/:w:/r/Shared%20Documents/CAS/Marketing%20Strategy%20Future.docx?d=w351c74af7d9e412d9cb2e0b5590c3498&csf=1&e=TWfoVC

Note that a sharing link shows the tenant followed by a long string of crap, and the non-sharing link, while also containing its share of trailing junk, also seems to incorporate a physical path as part of its structure. So using this pattern you should be able to tell if a Copy Link resulted in broken inheritance.

My thoughts on this

You have some options for setting the default behavior of this function, but like I said the default default is the most permissive. The decision to have it behave this way vexes me somewhat. In previous versions of SharePoint it’s been difficult and tedious to break permission inheritance through the UI, and I think it ought to be that way. Breaking inheritance should only be done with serious consideration as it’s difficult to support and also has performance implications – a Microsoft employee once told me that breaking inheritance “makes SQL cry”. Maybe in the cloud we care less about performance implications because all that stuff is abstracted away. But it’s still there and I’d have to believe Microsoft cares about its servers. Anyway…

Know your tenant settings

We can manage the tenant-wide default behavior for Copy Link by navigating directly to https://-admin.sharepoint.com/_layouts/15/online/ExternalSharing.aspx

There are a number of settings related to Sharing on this page but the ones we care about are under the headings “Default Link Type” and “Default Link Permission”. The defaults look like this.

Tenant Settings

Note that in the Copy Link dialog we had four options for how to share the link, and the tenant setting only allows for three, excluding, maddeningly, the “People with Existing Access” option, the one I think should be the default. If we select the “Direct – specific people” option, though, and just not actually specify any people, the result will be the same.

The “Use shorter links” option only substitutes the “guestaccess.aspx” url with the crypic sharing url we saw earlier, nothing really to see there. The Default Link Permission setting, if set to Read, will at least limit the damage done if files are inadvertently shared to the general population.

Manipulating the settings using PowerShell

Of course these settings can be set using PowerShell at both the Tenant and Site Collection level. The Site Collection level settings will override the Tenant level settings for the site in question. Check out the documentation for Set-SPOTenant and Set-SPOSite. The options you want to look into are, on both commands, DefaultSharingLinkType and DefaultSharingLinkType. Make sure to check out the other settings related to sharing just to get a feel for how they work.

 

Create a Yammer Group with Microsoft Flow

Microsoft Flow is a fantastic enterprise tool and comes with hundreds of default actions, which allow you to easily perform integrations to different services, including Yammer.

Flow gives us several actions out of the box that we can use to perform integration activities against Yammer:

1

These actions pretty much revolve around fetching and creating messages. True, this is the core thing we do in Yammer, but sometimes our requirements force us to step outside the default capabilities of our platforms and think of creative ways to solve complex problems.

We do a lot of Yammer integrations in our solutions at Rightpoint, and creating a Yammer group is something we do all the time. As we’ve seen, Flow doesn’t give us an action to create Yammer groups, but there is a Yammer API that will do this, and it can be very easily executed via Flow. (Technically speaking, the API to create Yammer groups is an undocumented API. We’ll discuss what that means a little later.)

We’re going to achieve this by POST-ing the necessary data to a Yammer API endpoint, using Flow’s HTTP action.  The HTTP action is, in my opinion, the most powerful and flexible Flow component. It’s so powerful because we can literally do anything we want.  At a low enough level of abstraction, every action is an HTTP action anyway.

Authenticating to Yammer

The Yammer API uses Oauth tokens to authenticate, so before we start our Flow we’ll need to create an app in Yammer. Navigate to https: //www.yammer.com/YOUR_ORG_NAME/client_applications, and click the green “Register New App” button.

On the “Register New App” screen, fill out the required fields. Absolutely none of the fields in this form have any bearing whatsoever on what we’re doing. If you’re planning to build a web app and publish it in the global Yammer app marketplace, these fields will be needed, but 99.9% of the time they’re pointless. But they’re required fields, so put in whatever will allow the validation to pass.

2

What we’re really after is the Oauth token. When we save our app, we’ll be redirected to a configuration page where we’ll see the Client ID and Client Secret. By clicking the “Generate a developer token” link, we will expose the app’s token. Don’t worry about the text claiming that this is for testing purposes; they’re still assuming you’re building web apps for the global store. Auth tokens in that case are generated on the client side for each user.

3

Won’t this Auth token expire?

Yammer app tokens last a long time, although Yammer won’t disclose exactly what the expiration terms are. I can say that I’ve had Yammer integrations authenticating in this fashion since about 2014, and I’ve never seen one expire. They can be revoked, however, and the account that created the app has the ability to do this.

Yammer Apps – other considerations

There are a few things you’ll want to know as you develop Yammer apps in this fashion:

  • Anyone can create a Yammer App. You don’t need to be an administrator to do this.
  • Yammer Apps execute under the security context of the creating user account. Content created by the app will appear to have been created by the user that created the app. Think of it this way: through the auth token the app author is delegating their access to anyone who holds it.
  • If your token is compromised you can invalidate it by navigating to yammer.com/YOUR_ORG_NAME/account/applications and click the “Revoke Access” link next to your app.
  • Consider using a dedicated “Service Account” for creation of Yammer Apps. Not only does this protect your user account should the token get compromised, it ensures the token continues to work should your account get disabled – for example, if you leave the organization.

Understanding the Yammer group creation API

If you do any work with the Yammer API, you’ll want to check out the Yammer API documentation.

There you’ll find more detailed information about using the API, and you’ll see a listing of all the supported endpoints exposed via the API.

Notice that there is no listed endpoint to create groups. This is because the group creation endpoint is undocumented. Something to consider when working with undocumented endpoints is that Yammer is not bound to provide support for it, nor will they feel obliged to maintain backward compatibility should they ever decide to update their APIs. So there’s an element of risk to working with these endpoints, and you should be prepared to accept that one morning you might wake up to find that all your stuff is broken.  I would counter that by saying Office 365 often imposes breaking changes even on supported stuff, and these APIs have been stable for a number of years running.

The endpoint we use to create groups in Yammer looks like this:

https://www.yammer.com/api/v1/groups.json?name=GROUP_NAME&private=false&show_in_directory=true

We will POST to this URL, add a content-type of application/json, and add the Yammer Auth token as a bearer token, and leave the body empty.  The parameters should be self-evident, and the last two are optional, and they default to a public, listed group.

Let’s test this out. We can use Fiddler or Postman for this, but I’ve recently discovered the Visual Studio Code REST Client extension, and that’s what I’ll be using here. You can read more about it here.

Set your request to look like this:

4

It’s a simple as that. If you did everything right, you should get a 202 response back and your new group will be shown in Yammer, along with a notification sent to All Company:

5

Remember, you’ll want to use a service identity, which I didn’t do in this case.

Creating our Flow

Now that we’ve figured out how to post to Yammer using the raw API, let’s incorporate that into a Flow. In my Flow I’m going to use an HTTP trigger, so I can call this as a service from other applications or even from other Flows.  We’re going to pass three parameters into our Flow trigger, groupName, isPrivate, and showInDirectory.  We’ll use the sample JSON option to generate the request body our trigger will be expecting:

6

Next we’ll create a variable to construct our REST API URL. Its configuration, using the same URL structure we discussed before, using the Trigger Body JSON to flesh out the parameters, will look like this:

7.png

Now we can create and configure our HTTP action:

8

Now, assuming we’ve hooked everything up properly, we can call our Flow. I’ll be using the VS Code extension again just to keep things simple:

9

If all goes well we’ll get a 201 response and our group will be present in Yammer:

10

Note that I passed in parameters to create a private, unlisted group, and you can see this group is private and won’t be listed in the Groups list on Yammer. Also, it doesn’t create the notification message in All Company. Note that the creation of public unlisted groups is unsupported and will cause an error response to be thrown.

Wrapping it up

In this post I showed a technique for integrating the Yammer API with Microsoft Flow, and used it to create groups in Yammer.  Using Flow’s HTTP actions we can do just about anything that can be done over HTTP.  For more info on the Yammer REST APIs, check out their official documentation.

Microsoft Flow: First Impressions

Over the last several weeks I’ve had my first experiences using Microsoft Flow in a real-world application. The client has dozens of old 2010-style SharePoint Designer workflows touching a number of business functions: Sales, Procurement, Change Management, and Human Resources, and they were looking for a way to modernize their development process and eliminate some of the quirks and irksome bugs that have been plaguing their users.  Hearing that the client was looking down the road at moving from on-premises SharePoint Server 2013 to the cloud, I recommended re-writing a number of these processes in Flow instead of SPD.

flow

Flow is a part of Microsoft’s new cloud-based platform for process modeling, for lack of a better phrase. The idea is that non-developers can use Flow’s intuitive user interfaces to build robust integrations between their line of business applications with no code anywhere to be found.

At first glance, Flow seems to be a huge improvement over the experience of building workflows in SharePoint Designer. For starters, it’s web-based, so there’s nothing to install. Flow comes with an impressive array of standard integration points (“connectors”), a handful of entry points (“triggers”) and hundreds of pre-defined activities you can configure (“actions”).  By dragging and dropping widgets onto the control surface and setting up some basic properties, power users can create powerful applications without having to rely on developers or IT to set it up for them.

Here are a few quick takeaways from my experiences so far.

Low expectations

SharePoint Designer workflows come with so much baggage it’s difficult to imagine preferring it to any succeeding technology that comes along. So the bar here is low.

Wide range of capability

Flow’s range of out-of-the-box integration points is very impressive, and they keep adding new connectors and actions all the time. There’s even an extension model where you can create your own and submit them for inclusion in the platform.

More of a consumer focus

Many of the integration points, though, don’t seem to make a lot of sense in most enterprise scenarios. Twitter, Facebook, and Gmail are some such connectors. And many of the starter templates are more in the personal productivity realm. For example,

  • Text me when I get an email from my boss
  • Email me when a new item shows up in a SharePoint list
  • Start a simple approval process on a document when it’s posted
  • Save Tweets to an Excel file
  • Send me an email reminder every day

 

Easy to extend

It’s really simple to create extension points in Flow. Suppose you have a need to do something that isn’t supported by a Flow action. If you can code, you can write an API to do what you need, and call it via an HTTP action.  Azure Functions work really well for this. In fact, the HTTP action is the most powerful thing in Flow. You can even use it to trigger other Flows from within a Flow.

Approvals are not fully baked

If you’re building approval workflows and are expecting the way SharePoint Designer works, you’ll be disappointed. An Approval in Flow consists of an email and a two buttons, nothing more. There is no concept of setting a status on an item, no functionality for logging (unless you roll it yourself), and no notion of tasks. It changes the way you think about approvals in general, because the old model just doesn’t apply here.

The Designer does not scale

For a simple two- or three-step flow, the designer works great. Add a couple of nested if/else blocks (‘conditions’), or more than a half-dozen or so actions, and you’ll find that  the design surface is totally unsuited to the task. Scroll bars are in difficult-to-find places and it’s often next to impossible to maintain your context when trying to move around within a Flow.

Sometimes saving a Flow will trigger a phantom validation error, and you’ll have to expand every one of your actions until you find the offending statement, because the Flow team have not seen fit to provide any sort of feedback on where the failure occurred. In addition, sometimes, especially when working with variables, the validation will fail even though the variable is properly configured.

No Code view

As clunky as the designer gets, if you’re a developer you might be more comfortable just coding your Flow the old fashioned way – after all, it’s just JSON under the hood. But alas, code view is not available in Flow. The design view is all you have.

Another implication of this: If you have places in your Flows where there are large blocks of similar functionality, you have no option to copy blocks of code and modify to suit. You’re stuck having to re-create those similar blocks of functionality, manually, in the designer, every single time. Believe me, this gets old really fast.

No versioning

If you make a change to your Flow and somehow break it, well, that’s tough, you’d better figure it out because there’s no rolling back.

Clearly Flow is not the magic bullet in the Enterprise process modeling world. It has is quirks and its pitfalls. But remember, the bar is low due to the legacy application it replaces.  SharePoint Designer workflows share many of the same deficiencies as Flow: a clumsy design experience (check), an inability to edit code directly (for all practical purposes), and no rollback model (technically possible in SPD via version history but janky as hell).

Given that SPD has had its ten-plus years in the limelight, and Flow is a brand-new V1 product with an engaged product team, I’d say the future looks bright for Flow.