Loading...

Part 1 - Multichannel Notification System with Azure Communication Services and Azure Functions

Part 1 - Multichannel Notification System with Azure Communication Services and Azure Functions

In the interconnected digital era, it's crucial for businesses and services to communicate effectively with their audience. A robust notification system that spans various communication channels can greatly enhance user engagement and satisfaction.

 

This blog post is part 1 of the two-part tutorial for a step-by-step guide on building such a multichannel notification system with Azure Functions and Azure Communication Services.

 

Leveraging serverless architecture and the reach of Azure Communication Services, your application can dynamically generate and send messages via SMS, Email, and WhatsApp. By incorporating OpenAI GPTs, the system can create content that is not only relevant and timely but personalized, making communication more impactful.

 

Example email

MilanKaur_0-1729897411266.png

 

Architecture diagram

MilanKaur_1-1729897450189.png

 

Here are some practical scenarios where a multichannel notification system is valuable: 

  • Financial Alerts: Banks and financial services can send fraud alerts, transaction confirmations, and account balance updates. 
  • Healthcare Reminders: Clinics and pharmacies can notify patients about appointment schedules, vaccinations, or prescription refills. 
  • Security Verification: Services requiring secure authentication can utilize two-factor authentication prompts sent via SMS or WhatsApp. 
  • Marketing and Promotions: Retailers can craft and distribute targeted marketing messages and promotions, driving customer engagement. 

The foundation of this solution is Azure Functions, for event-driven platform for running scalable applications and Azure Communication Services, for reliable Email, SMS, and WhatsApp messaging. To generate content, we use OpenAI GPTs, which enables the creation of sophisticated, context-aware text that can be used in notifications. 

 

Now, let's get started on your path to building a serverless messaging system on Azure. 

Prerequisites

Before we dive into building our multichannel notification system with Azure Functions and Azure Communication Services, you will need to ensure that the following tools and accounts set up:

  1. Azure Account: You need a Microsoft Azure account to create and manage resources on Azure. If you haven't got one yet, you can create a free account here.
  2. Visual Studio Code: We use Visual Studio Code (VS Code) as our Integrated Development Environment (IDE) for writing and debugging our code. Download and install it from here.
  3. Azure Functions Extension for Visual Studio Code: This extension provides you with a seamless experience for developing Azure Functions. It can be installed from the VS Code marketplace.
  4. C# Dev Kit: Since we write our Azure Functions in C#, this extension is necessary for getting C# support in VS Code. You can install it from the VS Code marketplace.
  5. Azure CLI: The Azure Command-Line Interface (CLI) will be used to create and manage Azure resources from the command line. For installation instructions, visit the Azure CLI installation documentation page.
  6. Postman: Although not strictly necessary, Postman is a handy tool for testing our HTTP-triggered Azure Functions without having to write a front-end application. You can download Postman from getpostman.com.

With the prerequisites in place, you're ready to set up your development environment, which we will cover in the following section.

Creating Resources

To get started with building a multichannel notification system, we'll need to create several resources within Azure. This section will walk you through setting up your Azure environment using the Azure CLI. Ensure that you have the Azure CLI installed on your machine and that you're logged into your Azure account.

 

Azure Communication Services

  1. Azure Communication Services (ACS) provides the backbone for our notification system, allowing us to send SMS, Email, and WhatsApp messages. Follow these steps to create resources for all three communication channels. However, you can choose one or more depending upon your preference. Log in to Azure:

    az login​

     

  2. Create a Resource Group (if necessary): This groups all your resources in one collection.

    az group create --name <YourResourceGroupName> --location <PreferredLocation>​


    Replace <YourResourceGroupName> with a name for your new resource group and <PreferredLocation> with the Azure region you prefer, such as eastus.

 
  1. Create ACS Resource: This will be the main ACS resource where we manage communications capabilities.

    az communication create --name <YourACSResourceName> --location Global --data-location UnitedStates --resource-group <YourResourceGroupName>​


    Replace <YourACSResourceName> with a unique name for your ACS resource and <YourResourceGroupName> with the name of your resource group.

    After creating the resource, retrieve the connection string as you will need it to connect your Azure Function to ACS. Copy the one marked as primary.

    az communication list-key --name <YourACSResourceName> --resource-group <YourResourceGroupName>

 

Azure Communication Services for Email

To set up Azure Communication Services Email, you'll need to follow a few steps in the Azure Portal:

  1. Create the Email Communications Service resource using the portal: Provision a new Email Communication Services resource in Azure portal using the instructions here. Make sure to select the same resource group as your ACS resource.

    MilanKaur_2-1729897705221.png

    MilanKaur_3-1729897705248.png

  2. Configure the Email Communications Service: You will need to configure domains and sender authentication for email. Provision an Azure Managed Domain or set up your Custom Verified Domain depending on your use case.

    MilanKaur_4-1729897705215.png

 

Azure Communication Services for SMS

To send SMS messages, you will need to acquire a phone number through ACS. You will have to submit a phone number verification application for enabling the number for sending or receiving SMS. This may take a couple of weeks. You can choose to skip SMS and continue the tutorial with Email and WhatsApp.

 

  1. Get a Phone Number: Navigate to the Phone Numbers blade in your ACS resource on the Azure portal and follow the steps to get a phone number that's capable of sending and receiving SMS.

    MilanKaur_5-1729897705189.png

  2. Toll Free verification: Apply for verification of your number using Apply for toll-free verification.

  3. Note the Phone Number: After acquiring a phone number, record it to use when sending SMS messages from your Azure Function.

    MilanKaur_6-1729897705206.png

 

WhatsApp for Business

Sending WhatsApp messages requires setting up a WhatsApp Business account.

  1. Set up a WhatsApp Business Account: Follow the instructions for connecting a WhatsApp business account with Azure Communication Services.
  2. Note the WhatsApp Configuration: Once set up, make a note of the necessary configuration details such as the phone number and WhatsApp Business API credentials, as they will be needed in your Azure Function.

    MilanKaur_7-1729897705213.png

By following these steps, you create the resources needed to build a multichannel notification system that can reach users through SMS, Email, and WhatsApp. Next, we set up your Azure Function and integrating these services into it.

 

Setting Up The Environment

With the prerequisites out of the way, let's prepare our environment to develop our multichannel notification system using Azure Functions and Azure Communication Services.

Creating the Function App Project

Open Visual Studio Code and follow these steps to create a new Azure Functions project:

  1. Click on the Azure icon in the Activity Bar on the side of Visual Studio Code to open the Azure Functions extension.
  2. In the Azure Functions extension, click on the Create New Project icon, choose a directory for your project, and select Create New Project Here.

    MilanKaur_0-1729898184436.png

 

  1. Choose the language for your project. We select C# for this tutorial.
  2. Select the template for your first function. For this project, an HTTP-triggered function is a good starting point since we want to receive HTTP requests to send out notifications.
  3. Provide a function name, such as EmailTrigger, and set the authorization level to anonymous or function, depending on your security preference.

After you have completed these steps, your Azure Functions project is set up with all the necessary files in the chosen directory.

 

Installing the Necessary Packages

Now it’s time to add the packages necessary for integrating Azure Communication Services:

  1. Open the integrated terminal in Visual Studio Code by clicking on 'Terminal' in the top menu and then selecting 'New Terminal'.
  2. Add the Azure Communication Services packages to your project:

bash

dotnet add package Azure.Communication.Email dotnet add package Azure.Communication.Sms dotnet add package Azure.Communication.Messages --prerelease
 

Setting Up Environment Variables

You should store configuration details like connection strings and phone numbers as environment variables instead of hardcoding them into your functions. To do so in Azure Functions, add them to the local.settings.json file, which is used for local development.

Edit the local.settings.json file to include your Azure Communication Services (ACS) connection string and phone numbers:

json

{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "COMMUNICATION_SERVICES_CONNECTION_STRING": "<acs_connection_string>", "SENDER_PHONE_NUMBER": "<acs_sms_phone_number>", "WHATSAPP_NUMBER": "<acs_whatsapp_number>", "SENDER_EMAIL_ADDRESS": "<acs_email_address>" } }
 

Be sure to replace <acs_connection_string>, <acs_sms_phone_number>, <acs_whatsapp_number>, and <acs_email_address> with your actual Azure storage account connection string, Azure Communication Services connection string, SMS phone number, WhatsApp number, and sending email address.

Remember not to commit the local.settings.json file to source control if it contains sensitive information. Configure similar settings in the Application Settings for your Azure Function when you deploy to Azure.

Coding the EmailTrigger

Creating a functional EmailTrigger Azure Function involves starting from the default template provided by Azure Functions for C# and enhancing it with the necessary logic and services to handle email sending. In this section, we guide you through the steps to transform the default template into the finished EmailTrigger function.

 

Step 1: Set Up the Function Template

Start by using the default HTTP triggered function template provided by Visual Studio Code for creating an Azure Functions project. It will have the necessary usings, function name attribute, and a simple HTTP trigger that returns a welcome message. Select your project in the Workspace pane and click on the 'Create Function' button in the Azure Functions extension. Choose 'HTTP trigger' as the template and provide a name for the function, such as EmailTrigger. Set the authorization level to anonymous or function, depending on your security preference.

MilanKaur_1-1729898184426.png

 

Step 2: Add Azure Communication Services Email Reference

Add a reference to using Azure.Communication.Email then create a property in the EmailTrigger class to hold an instance of EmailClient and a property to hold the email sender address.

csharp

private readonly EmailClient _emailClient; private string? sender = Environment.GetEnvironmentVariable("SENDER_EMAIL_ADDRESS");
 

Step 3: Read Configuration and Initialize EmailClient

Within the EmailTrigger class constructor, read the Azure Communication Services connection string from the environment variables using Environment.GetEnvironmentVariable() method and initialize an instance of EmailClient with the connection string.

Make sure to handle the possibility that the environment variable may be null and throw an appropriate exception if it is not set.

csharp

string? connectionString = Environment.GetEnvironmentVariable("COMMUNICATION_SERVICES_CONNECTION_STRING"); if (connectionString is null) { throw new InvalidOperationException("COMMUNICATION_SERVICES_CONNECTION_STRING environment variable is not set."); } _emailClient = new EmailClient(connectionString);
 

Step 4: Define the Request Model

Create a request model class EmailRequest inside the EmailTrigger class to represent the expected payload. This model includes the subject, HTML content, and recipient email address.

csharp

public class EmailRequest { public string Subject { get; set; } = string.Empty; public string HtmlContent { get; set; } = string.Empty; public string Recipient { get; set; } = string.Empty; }
 

Step 5: Parse the Request Body

Modify the Run function to be async since we'll be performing asynchronous operations.

csharp

public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req)
 

Use StreamReader to read the request body and deserialize it into the EmailRequest object using System.Text.Json.JsonSerializer.

Handle the case where the deserialization fails by returning a BadRequestResult.

csharp

string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); EmailRequest? data = JsonSerializer.Deserialize<EmailRequest>(requestBody, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); if (data is null) { return new BadRequestResult(); }
 

Step 6: Define the Sender and Send the Email

Instantiate a sender email address string that will be passed to the SendAsync method of the EmailClient instance. Replace the static email '[email protected]' with your configured sender address in the actual implementation.

Use a try-catch block to send the email using the SendAsync method and catch any RequestFailedException to log any errors.

csharp

_logger.LogInformation("Sending email..."); EmailSendOperation emailSendOperation = await _emailClient.SendAsync( Azure.WaitUntil.Completed, sender, data.Recipient, data.Subject, data.HtmlContent ); _logger.LogInformation($"Email Sent. Status = {emailSendOperation.Value.Status}"); _logger.LogInformation($"Email operation id = {emailSendOperation.Id}");
 

Step 7: Return a Success Response

Once the email send operation is completed, return an OkObjectResult indicating the success of the operation.

csharp

return new OkObjectResult("Email sent successfully!"); }
 

Final Code

After completing all the above steps, your EmailTriggerAzure Function should look as follows:

csharp

using System; using System.IO; using System.Text.Json; using System.Threading.Tasks; using Azure; using Azure.Communication.Email; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; namespace ACSGPTFunctions { public class EmailTrigger { private readonly ILogger<EmailTrigger> _logger; private readonly EmailClient _emailClient; public EmailTrigger(ILogger<EmailTrigger> logger) { _logger = logger; string? connectionString = Environment.GetEnvironmentVariable("COMMUNICATION_SERVICES_CONNECTION_STRING"); if (connectionString is null) { throw new InvalidOperationException("COMMUNICATION_SERVICES_CONNECTION_STRING environment variable is not set."); } _emailClient = new EmailClient(connectionString); } public class EmailRequest { public string Subject { get; set; } = string.Empty; public string HtmlContent { get; set; } = string.Empty; public string Recipient { get; set; } = string.Empty; } [Function("EmailTrigger")] public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req) { _logger.LogInformation("Processing request."); string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); EmailRequest? data = JsonSerializer.Deserialize<EmailRequest>(requestBody, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); if (data is null) { return new BadRequestResult(); } var sender = "[email protected]"; try { _logger.LogInformation("Sending email..."); EmailSendOperation emailSendOperation = await _emailClient.SendAsync( Azure.WaitUntil.Completed, sender, data.Recipient, data.Subject, data.HtmlContent );  _logger.LogInformation($"Email Sent. Status = {emailSendOperation.Value.Status}"); _logger.LogInformation($"Email operation id = {emailSendOperation.Id}"); } catch (RequestFailedException ex) { _logger.LogInformation($"Email send operation failed with error code: {ex.ErrorCode}, message: {ex.Message}"); return new ObjectResult(new { error = ex.Message }) { StatusCode = 500 }; } return new OkObjectResult("Email sent successfully!"); } } }
 

This completed EmailTriggerAzure Function is now ready to be part of a multichannel notification system, handling the email communication channel.

Next Steps

Continue to the next part of this topic to further explore building, deploying and testing your intelligent app for a multichannel notification system.

Published on:

Learn more
Azure Communication Services Blog
Azure Communication Services Blog

Azure Communication Services Blog articles

Share post:

Related posts

Integrate Dataverse Azure solutions – Part 2

Dataverse that help streamline your integrations, such as Microsoft Azure Service Bus, Microsoft Azure Event Hubs, and Microsoft Azure Logic A...

2 days ago

Dynamics 365 CE Solution Import Failed in Azure DevOps Pipelines

Got the below error while importing Dynamics CRM Solution via Azure DevOps Pipeline. 2024-12-18T23:14:20.4630775Z ]2024-12-18T23:14:20.74...

3 days ago

Dedicated SQL Pool and Serverless SQL in Azure: Comparison and Use Cases

Table of Contents Introduction Azure Synapse Analytics provides two powerful SQL-based options for data processing: Dedicated SQL Pools and Se...

3 days ago
Stay up to date with latest Microsoft Dynamics 365 and Power Platform news!
* Yes, I agree to the privacy policy