M
MilanKaur
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
Architecture diagram
Here are some practical scenarios where a multichannel notification system is valuable:
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.
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:
With the prerequisites in place, you're ready to set up your development environment, which we will cover in the following section.
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.
To set up Azure Communication Services Email, you'll need to follow a few steps in the Azure Portal:
To send SMS messages, you need to acquire a phone number through Azure Communication Services. You need 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.
Sending WhatsApp messages requires setting up a WhatsApp Business account.
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.
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.
Open Visual Studio Code and follow these steps to create a new Azure Functions project:
After you have completed these steps, your Azure Functions project is set up with all the necessary files in the chosen directory.
Now it’s time to add the packages necessary for integrating Azure Communication Services:
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
Edit the
Be sure to replace
Remember not to commit the
Creating a functional
Start by using the default HTTP triggered function template provided by Visual Studio Code for creating an Azure Functions project. It has 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 Create Function in the Azure Functions extension. Choose HTTP trigger as the template and provide a name for the function, such as
Add a reference to using
Within the
Make sure to handle the possibility that the environment variable may be null and throw an appropriate exception if it is not set.
Create a request model class
Modify the
Use
Handle the case where the deserialization fails by returning a
Instantiate a sender email address string that that is passed to the
Use a try-catch block to send the email using the
Once the email send operation is completed, return an
After completing all the above steps, your
This completed
Continue to the next part of this topic to further explore building, deploying and testing your intelligent app for a multichannel notification system.
Continue reading...
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
Architecture diagram
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.
Prerequisiteshttps://azure.github.io/Cloud-Nativ...tichannel-notification-system-1#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:
- 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.
- 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.
- 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.
- 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.
- 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.
- 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 Resourceshttps://azure.github.io/Cloud-Nativ...nnel-notification-system-1#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 Serviceshttps://azure.github.io/Cloud-Nativ...ication-system-1#azure-communication-services
- Azure Communication Services 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
- 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 aseastus
.
- Create Azure Communication Services Resource: This is the main Azure Communication Services 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 Azure Communication Services resource and<YourResourceGroupName>
with the name of your resource group.
After creating the resource, retrieve the connection string as you need it to connect your Azure Function to Azure Communication Services. Copy the one marked as primary.
az communication list-key --name <YourACSResourceName> --resource-group <YourResourceGroupName>
Azure Communication Services for Emailhttps://azure.github.io/Cloud-Nativ...stem-1#azure-communication-services-for-email
To set up Azure Communication Services Email, you'll need to follow a few steps in the Azure Portal:
- 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 Azure Communication Services resource.
- Configure the Email Communications Service: You 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.
Azure Communication Services for SMShttps://azure.github.io/Cloud-Nativ...system-1#azure-communication-services-for-sms
To send SMS messages, you need to acquire a phone number through Azure Communication Services. You need 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.
- Get a Phone Number: Navigate to the Phone Numbers blade in your Azure Communication Services resource on the Azure portal and follow the steps to get a phone number that's capable of sending and receiving SMS.
- Toll Free verification: Apply for verification of your number using Apply for toll-free verification.
- Note the Phone Number: After acquiring a phone number, record it to use when sending SMS messages from your Azure Function.
WhatsApp for Businesshttps://azure.github.io/Cloud-Nativ...l-notification-system-1#whatsapp-for-business
Sending WhatsApp messages requires setting up a WhatsApp Business account.
- Set up a WhatsApp Business Account: Follow the instructions for connecting a WhatsApp business account with Azure Communication Services.
- 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 are needed in your Azure Function.
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 Environmenthttps://azure.github.io/Cloud-Nativ...-notification-system-1#setting-up-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 Projecthttps://azure.github.io/Cloud-Nativ...on-system-1#creating-the-function-app-project
Open Visual Studio Code and follow these steps to create a new Azure Functions project:
- Click on the Azure icon in the Activity Bar on the side of Visual Studio Code to open the Azure Functions extension.
- In the Azure Functions extension, click on the Create New Project icon, choose a directory for your project, and select Create New Project Here.
- Choose the language for your project. We select C# for this tutorial.
- 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.
- 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 Packageshttps://azure.github.io/Cloud-Nativ...on-system-1#installing-the-necessary-packages
Now it’s time to add the packages necessary for integrating Azure Communication Services:
- Open the integrated terminal in Visual Studio Code by clicking on 'Terminal' in the top menu and then selecting 'New Terminal'.
- Add the Azure Communication Services packages to your project:
bash
Code:
dotnet add package Azure.Communication.Email
dotnet add package Azure.Communication.Sms
dotnet add package Azure.Communication.Messages --prerelease
Setting Up Environment Variableshttps://azure.github.io/Cloud-Nativ...ion-system-1#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 connection string and phone numbers:json
Code:
{
"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 EmailTriggerhttps://azure.github.io/Cloud-Nativ...notification-system-1#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 Templatehttps://azure.github.io/Cloud-Nativ...-system-1#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 has 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 Create Function 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.Step 2: Add Azure Communication Services Email Referencehttps://azure.github.io/Cloud-Nativ...-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
Code:
private readonly EmailClient _emailClient;
private string? sender = Environment.GetEnvironmentVariable("SENDER_EMAIL_ADDRESS");
Step 3: Read Configuration and Initialize EmailClienthttps://azure.github.io/Cloud-Nativ...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
Code:
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 Modelhttps://azure.github.io/Cloud-Nativ...tion-system-1#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
Code:
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 Bodyhttps://azure.github.io/Cloud-Nativ...cation-system-1#step-5-parse-the-request-body
Modify the
Run
function to be async since we'll be performing asynchronous operations.csharp
Code:
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
Code:
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 Emailhttps://azure.github.io/Cloud-Nativ...1#step-6-define-the-sender-and-send-the-email
Instantiate a sender email address string that that is passed to the
SendAsync
method of the EmailClient instance. Replace the static email 'DoNotReply@effaa622-a003-4676-b27e-6b9e7a783581.azurecomm.net' 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
Code:
_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 Responsehttps://azure.github.io/Cloud-Nativ...ion-system-1#step-7-return-a-success-response
Once the email send operation is completed, return an
OkObjectResult
indicating the success of the operation.csharp
Code:
return new OkObjectResult("Email sent successfully!");
}
Final Codehttps://azure.github.io/Cloud-Nativ...multichannel-notification-system-1#final-code
After completing all the above steps, your
EmailTriggerAzure Function
should look as follows:csharp
Code:
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 = "DoNotReply@effaa622-a003-4676-b27e-6b9e7a783581.azurecomm.net";
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 Stepshttps://azure.github.io/Cloud-Nativ...multichannel-notification-system-1#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.
Continue reading...