A few years back, I added a donations page to Have I been pwned (HIBP). Now as I explained at the time, I didn't particularly need them to cover my hard-cash outgoings because I run the thing on a shoestring, but as I explain on that page, it takes a massive amount of effort. If people want to fling me a coffee or some beers, that's just great and I appreciate it enormously. Problem is, it's hard to individually show that appreciation. Especially during a busy period, I can end up with a lot of coffee and I can't realistically reply to each and every person by email thanking them or I end up with exactly the problem I describe on the donations page - no more time! But I did want to send them a thanks anyway, so here's what I did:
Donations are primarily done via PayPal. I get some via Bitcoin as well but notifications of a payment via BTC don't include any identifiable information about who's sending it. PayPal, on the other hand, sends me an email similar to this one:
This is great - I love beer! I have a rule in Outlook.com to file these away into a "Donations" folder and normally, that would be that. But wouldn't it be nice to send a little thank you? Here's where Microsoft Flow comes into play. It's a similar deal to IFTTT which I've used quite extensively over the years but as you'd expect, Flow plays a little nicer with the Microsoft things (i.e. native integration with Azure storage). I wanted to do some processing with these emails so I created a new Flow like this:
This is actually the execution of the flow and there's a unique one for every single donation. I'll drill down on that in a minute but for now, notice how it ran at 20:35:26 last Friday and the donation email from PayPal above shows a transaction time of 20:35:03. That's their time stamp too so the 23 second period encompasses them sending it, Outlook.com receiving it, processing the rule to put it in the "Donations" folder then Flow picking up the message. You can see a "trigger" and an "action" in the diagram above, let's take a look inside that trigger:
Here you're seeing "Inputs" which define the trigger conditions for Outlook.com and then "Outputs" which is everything it can pull from the message. The inputs show that once a message appears in that "Donations" folder, it doesn't matter what the importance is or if it has any attachments, it's going to get processed. In the "Outputs" we see everything from who sent it, to the subject to the body and a bunch of other self-explanatory attributes. The question now is what should be done with this which takes us to the action:
This is taking the entire message and dropping it an Azure Storage Queue. So far, we've been looking at the output of when the Flow runs, but let's take a look at the editor view to see how this works:
That's it - just dump the body into the queue! Question now is what to do next..
I actually wanted to achieve 3 outcomes from this exercise:
- Send a thank you email a little while after the donation
- Store the donor's address and PayPal transaction ID in HIBP
- Include a link to subscribe to my blog (but only if they're not already subscribed)
This was going to take some code because I was going to need to put data into HIBP's relational database as well as connect to MailChimp to see if the donor had already subscribed to my blog (I didn't want to bug them with that otherwise). I decided to do this with a WebJob and I've written about my love of these in the past. And so it all began like this:
public static void ProcessQueueMessage([QueueTrigger("donation")] string donationEmail, TextWriter log)
That donationEmail string is the entire body of the mail from which I could extract both the transaction ID and the donor's email address via regex. Now in case you're thinking "But you could get all this via the PayPal API", I started down that path and found it painful for a number of reasons. In comparison, this was dead simple and does everything I need.
So a few lines of code go into the WebJob and I push it out to Azure. It's now monitoring that queue the donation emails are being dropped into and I can watch WebJob execution via the Azure Management Portal. Over there, I could see the donation I showed earlier hitting the WebJob courtesy of some diagnostic outputs I added:
The workflow within the WebJob then goes as follows:
- Check the HIBP database to see if the transaction ID has already been processed. I want this to be idempotent in case the same message comes in twice.
- Hit the MailChimp API using MailChimp.Net pulled from NuGet. This is to check if the donor's email address is already subscribed.
- If the transaction hasn't already been processed, prepare an email which may or may not also give them a link to subscribe to the blog.
Now it was just a matter of sending the email. I could have fired it out in a transactional way using SendGrid which I use for other HIBP emails, but I wanted to make it a little more personal. I decided to create another Flow:
This one kicks off with a "Request" action that fired at 20:36:33 so we're now 90 seconds into it. This action quite neat as it stands up an endpoint you can hit from your own app. When I configured it, all I had to do was define a schema for the inbound request:
This is literally just the donor's email address, the subject for the email and the body. The URL at the top of the image then has a great big obfuscated string and so long as I post to that from the WebJob above, I'll have myself a set of structured data. So I literally just created a corresponding model in .NET, serialised it and chucked it into an HttpClient then posted it off. When it ran as a result of the donation above, it looked like this:
Within the email body, there's a section about subscribing to my blog like this:
This is a link back to HIBP with a globally unique identifier that I saved on the donor's record when the WebJob was processing the email. When it's followed, I verify that the GUID is correct, pull the email address associated with it then hit MailChimp's API and subscribe the donor's email address. When all that works and they follow the link, they then show up in MailChimp:
So that's that done, the donor is opted in, let's get back to the Flow and you may have noticed earlier on that I have a delay in there:
The reason I'm doing this is that I didn't want to just suddenly hit the donor with an email before they'd barely closed the PayPal tab. I figured I'd give them a half hour, come back then send them a nice little email that feels more organic. Here's the action in the Flow that does that:
This is pretty self-explanatory and it's using the Outlook connector again but this time, obviously to send the email. Because I connected it under my own account, the sent items in my local copy of Outlook shows the message:
And it's a genuine email from my own account so no spam problems and if the recipient wants to reply and engage, they can.
I really like this for a number of reasons:
- It took me less time to build it than to write this blog post! It's dead simple.
- It's free for this volume of usage; you get 750 Flow executions per month and with 2 for each donation, I'd need to average more than 11 per day to exceed it.
- If I exceed it because of too many donations, $5 per month will give me 4.5k executions. This would be a good problem to have!
- Composing apps in this fashion where there are atomic units of work running independently and performing discrete tasks makes everything from troubleshooting to deployment to modifications dead simple.
This is a really neat little solution and the good news is that you can experience it firsthand yourself! All you need to do is start at the donations page... :)