In this post we'll use Azure Functions as a gateway that recieves a payload from Octopus Deploy (after a deployment to production) and posts a notification to a Microsoft Teams channel.

The Azure Function code for this blogpost can be found at


A few weeks ago Octopus Deploy released version 3.5 of the amazing deployment tool. In this version they introduced 'Subscriptions'. This feature allows you to subscribe to all kinds of events via email or webhook. Together with the release they also published a post, showcasing the use of 'Subscriptions' to send a notification of an Octopus Deploy event to a Slack channel via Zapier. Great idea, we usd Octopus Deploy at Natch, but... we don't use Slack, and I don't want to use Zapier. We did activate Microsoft teams recently, it comes for free with our Office 365 subscription and we are always looking to improve communication and workflow. So I got this idea:

Mission: post a message on a Microsoft Teams channel when Octopus Deploy has deployed an application in production, with Azure Functions in the middle

What is Azure Functions

With the announcement of Azure Functions going GA (General Availability) yesterday (2016-11-16), it seemed like the right time to write this blogpost. Azure Functions is Microsoft's implementation of the serverless computing model on top of Azure. Serverless computing has been the lastest evolution of the cloud. Amazon has had Lambda on AWS for two years already.

Azure Functions is a solution for easily running small pieces of code, or "functions," in the cloud.

We've come a long way. It started with buying physical hardware and running servers on them (been there, done that). Then came virtualization, renting resources, and running your VMs (IaaS). Evolving into platforms like Azure Website where you don't even own and maintain VMs anymore (PaaS). IaaS and Paas are still valid models, but you're paying for those resources 24/7 even if your application only runs a few hours a day or is only visited during office hours.

With serverless computing a lot of this changes. You only pay when your code is executed. You only maintain your code. The underlying infrastructure is taken care of for you by the hosting provider.

Microsoft used the WebJobs platform as a starting point for Azure Functions. With the amazing Azure portal, the online editor code-named 'Monaco', source control integration for CD, Azure Functions is set to be a great candidate when exploring options. A Function can be written in C# with Roslyn under the hood, but also Javascript with node under the hood.

What is Microsoft Teams

In short, Microsofts answer to Slack. Released just a few weeks back (2016-11-02).

Microsoft Teams, the new chat-based workspace in Office 365

I believe Slack got a little bit scared, because they released this passive-aggresive 'Welcome Microsoft Teams' press release right after Microsofts announcement.


To set this all up, we have 3 parts:

  • An Octopus Deploy Subscription that posts its payload to a webhook...
  • An Azure function that receives the payload, extracts the data and posts a message
  • A Microsoft Teams channel with an 'Incoming Webhook' connector

Microsoft Teams

We'll start at the last step of the flow, because we need the webhook url for the Azure Function.

In the channel, add a connector of the type 'Incoming Webhook'.

Create connector in Micrsoft Team channel

All you need is a name (ie. Octopus Deploy) and you'll get a webhook url back under the domain. You might also want to upload the Octopus logo, because that will be displayed with the message. You'll need the webhook url in the next step, keep it in the clipboard.

Setup connector

Azure Function

In the Azure portal, add a new Function App. This App allows you to add multiple 'functions'. We'll only need one, and we'll use 'GenericWebhookCSharp' as the starting point. This template is configured to run on an incoming http request.

Under the Application Settings of the Funtion App, add a new 'app setting' named 'TeamsWebHookUrl' and paste the O365 webhook url as the value. This app setting will be available as an environment variable when we write our C# code. You don't need to hardcode this setting, so you don't need to put this in source control.

Azure App setting

Copy the code from the github project (which I also set up as Continuous Integration source) or this gist.

Previously, without using a service like Zapier, I would have:

  • created an ASP.NET MVC/WebApi project -> too much work (lazy developer = good developer)
  • hosted it on a webserver (or azure) -> would run all the time (consume too much resources, expensive)

The code is very short and will be called a few times a day at most. Which is a great fit for an Azure Function.

Before we continue to the next step, copy the Function url from the Develop tab.

Azure Function url

Octopus Deploy

To activate a 'Subscription' you can either click around in Octopus Deploy until you stumble upon it or give up (yes, it's hidden very well). If you gave up, here iswhere you can find it: Configuration > Audit > Subscriptions (top right).

Create a new subscription. Give it a name, set filters and paste the Azure Function url in the 'Payload URL' field.

Create a subscription in Octopus Deploy

Finishing up

Now let's see if our setup works:

  • Trigger an Octopus Deploy event that matches the filters of the subscription you have set up.
  • In the Azure Portal, navigate to the monitor tab of your function, there is even a 'live event stream'
  • Within a few seconds, your Microsoft Teams channel will receive the message that was sent by Octopus Deploy.
  • Enjoy.

Message in Microsoft Teams after a deployment from Octopus Deploy

About writing the function

I started writing the code for the function in the Azure portal. The editor is pretty amazing, considering it's running in the browser. There a handy 'test' feature where you can quickly simulate a request to the function (which is more a webhook). This allows you to iterate quickly without leaving the browser. When the code was done (is code ever done?) I moved it to a github repo and set up the continuous integration option under the Function app settings. Now every commit in the master branch will automatically update the Azure function. So easy. I hadn't tried Azure functions before, nor had I used Octopus Deploy subscriptions or the Microsoft Teams webhook connector. Still I was able to get this all running in under 2 hours. Writing this blog post is actually more work.

Don't hesitate to leave a comment below or fork the github repo.