Sending to Azure Notification Hubs with Python

I’ve been working on a problem dealing with broadcast messages. How do I send a message “somewhere” and get it received by many systems elsewhere in a broadcast manner. This problem is excellently solved by Microsoft Azure Notification Hubs. Notification Hubs allows you to send a template message and have it be sent to an APNS (for iOS devices), Google Cloud Manager, or GCM (for Android devices), MPNS (for Windows Phone devices) or a Windows 8.1 toaster app or even something like Growl on the Mac. You do, of course, need to write an app for each of these and you need to write the broadcast message.

My first step in this was to create a notification hub. To do this, you sign up for Microsoft Azure, then go to the management portal and add a Notification Hub.

Once you have your notification hub created, you will want to get a couple of pieces of information. Specifically, you will need:

  • The Hub Name
  • The Connection String

You created the Hub Name, so you should be able to write that down. To get the connection string, log into the Microsoft Azure portal, select Service Bus, then your Notification Hub and open up the Dashboard. On the right hand side is the connection string.


Click on the Connection String. You will see two keys – one called DefaultListenSharedAccessSignature and the other called DefaultFullAccessSharedAccessSignature. You want the connection string associated with the latter. Just click on the Copy icon on the far right side to put it in your copy buffer.

My second step is to produce a library that can use REST to post to the Azure Notification API. You can download the Azure SDK for Python, but it doesn’t have the appropriate code for handling notification hubs. So I decided to roll my own. My first stop was to use urllib2 – a standard Python library. Unfortunately, I bumped into a bug. The REST API Documentation for Notification Hubs is excellent. If you read the documentation, you will note that you have to set the ServiceBusNotification-Format header to tell Azure Notification Hubs what sort of message you are sending. The bug in urllib2 is that your header object can say ServiceBusNotification-Format, but urllib2 helpfully does what it thinks is proper capitalization and changes it to Servicebusnotification-Format, which isn’t the same thing. It took some assistance from a pair of Microsoft Azure engineers to figure this out.

How to fix this? The Azure Engineer (thanks Piyush!) used the Requests library. I wanted to have a Python class and I wanted to not need additional libraries. So I rolled my own with httplib.

Here is the class:

import time, hmac, base64, hashlib, json, urllib, httplib
from urlparse import urlparse

class NotificationHub:
  def __init__(self, ConnectionString=None, HubName=None, debug=0):
    self.Endpoint    = None
    self.HubName     = HubName
    self.Debug       = debug
    parts = ConnectionString.split(';')
    for part in parts:
      if part.startswith('Endpoint'):
        self.Endpoint = 'https' + part[11:]
      if part.startswith('SharedAccessKeyName'):
        self.SasKeyName = part[20:]
      if part.startswith('SharedAccessKey'):
        self.SasKeyValue = part[16:]

  def get_expiry(self, secs):
    return int(round(time.time() + secs))
  def encode_base64(self, data):
    return base64.b64encode(data)
  def sign_string(self, to_sign):
    key = self.SasKeyValue.encode('utf-8')
    tos = to_sign.encode('utf-8')
    sig = hmac.HMAC(key, tos, hashlib.sha256)
    dig = sig.digest()
    enc = self.encode_base64(dig)
    return enc
  def sas_token(self, uri):
    target_uri = self.Endpoint + self.HubName + uri
    my_uri = urllib.quote(target_uri, '').lower()
    expiry = str(self.get_expiry(300))
    tos = my_uri + '\n' + expiry
    sig = urllib.quote(self.sign_string(tos))
    fmt = 'SharedAccessSignature sig={0}&se={1}&skn={2}&sr={3}'
    tok = fmt.format(sig, expiry, self.SasKeyName, my_uri)
    return tok
  def send_notification(self, message, msgtype='template'):
    rel_uri = '/messages?api-version=2013-10'
    url = self.Endpoint + self.HubName + rel_uri
    o = urlparse(url)
    headers = {
      'Content-Type': 'application/json;charset=utf-8',
      'ServiceBusNotification-Format': msgtype,
      'Authorization': self.sas_token(rel_uri),
      'Host': o.hostname,
      'Content-Length': len(message)
    if self.Debug > 0:
      print "--- REQUEST ---"
      print "URI: " + url
      print "Headers: " + json.dumps(headers)
      print "Payload: " + json.dumps(payload)
      print "--- END REQUEST ---"
    conn = httplib.HTTPSConnection(o.hostname, o.port)
    conn.request('POST', url, message, headers)
    response = conn.getresponse()
    if self.Debug > 0:
      print "--- RESPONSE ---"
      print str(response.status) + " " + response.reason
      print "--- END RESPONSE ---"

Your basic methodology here is to create a NotificationHub object then call send_notification. Something like this:

if __name__ == '__main__':
  payload = {
    'data': {
      'msg': 'Hello World!'
  nh = NotificationHub(cs, hubname, debug=1)
  nh.send_notification(json.dumps(payload), 'gcm')

Initially you will get a 400 response from this because you have not registered a broadcast listener app with your Azure Notification Hub. If you get some other message, then your linkage isn’t working properly. I’ll cover writing the code for a listener in a later blog post (although there are examples on the Azure Developer Site for Notification Hubs).