Skip to content

Commit

Permalink
Switch SendGrid Email Notification to AWS SnS (#191)
Browse files Browse the repository at this point in the history
* Switch SendGrid Email Notification to AWS SnS

* Limit 14 calls max per second

* Fix typo

* Auto Format

* Revert "Auto Format"

This reverts commit 5733a59.

* Fix Alignment Issue

* Fix Dave review comments

* Resolve formating issue

* Update NotificationSystem/SendSubscriberEmail.cs

Co-authored-by: Dave Thaler <dthaler1968@gmail.com>

* Update NotificationSystem/SendSubscriberEmail.cs

---------

Co-authored-by: Yuvaraj <yudurais@microsoft.com>
Co-authored-by: Dave Thaler <dthaler1968@gmail.com>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent 3b0b8e4 commit 133efb9
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 21 deletions.
3 changes: 2 additions & 1 deletion NotificationSystem/NotificationSystem.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.SimpleEmail" Version="3.7.401.11" />
<PackageReference Include="Azure.Storage.Queues" Version="12.11.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.10" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.SendGrid" Version="3.0.2" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.5" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.3" />
<PackageReference Include="RateLimiter" Version="2.2.0" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.33" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="4.0.1" />
Expand Down
8 changes: 4 additions & 4 deletions NotificationSystem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ In the moderators flow:

- A change in the Cosmos DB metadata store triggers the SendModeratorEmail function
- If there is a newly detected orca call that requires a moderator to validate, the function fetches the relevant email list
- The function then calls SendGrid to send emails to moderators
- The function then calls AWS Simple Email Service to send emails to moderators

In the subscribers flow:

- A change in the Cosmos DB metadata store triggers the DbToQueue function
- If there is a new orca call that the moderator has validated, the function sends a message to a queue
- The SendSubscriberEmail function periodically checks the queue
- If there are items in the queue, the function fetches the relevant email list
- The function then calls SendGrid to send emails to subscribers
- The function then calls AWS Simple Email Service to send emails to subscribers

## Get email list

Expand Down Expand Up @@ -111,7 +111,6 @@ All resources are located in resource group **LiveSRKWNotificationSystem**.
1. Storage account with queues, email template images and moderator/subscriber list: orcanotificationstorage
2. Metadata store (from which some functions are triggered): aifororcasmetadatastore
3. Azure function app: orcanotification
4. SendGrid account (for sending emails): aifororcas

## Run Locally
It is recommended to go to the "orcanotification" function app, then Settings > Configuration to find the app settings used.
Expand All @@ -127,7 +126,8 @@ Create local.settings.json in the current directory (NotificationSystem) using t

"OrcaNotificationStorageSetting": "<storage account connection string>",
"aifororcasmetadatastore_DOCUMENTDB": "<cosmos db connection string>",
"SendGridKey": "<SendGrid API key>",
"AWS_ACCESS_KEY_ID": "<AWS Access Key>",
"AWS_SECRET_ACCESS_KEY": "<AWS Secret Key>",
"SenderEmail": "<email address>"
}
}
Expand Down
16 changes: 11 additions & 5 deletions NotificationSystem/SendModeratorEmail.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System;
using Amazon;
using Amazon.SimpleEmail;
using RateLimiter;
using ComposableAsync;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Table;
Expand All @@ -7,13 +11,14 @@
using Microsoft.Extensions.Logging;
using NotificationSystem.Template;
using NotificationSystem.Utilities;
using SendGrid.Helpers.Mail;

namespace NotificationSystem
{
[StorageAccount("OrcaNotificationStorageSetting")]
public static class SendModeratorEmail
{
static int SendRate = 14;

[FunctionName("SendModeratorEmail")]
public static async Task Run(
[CosmosDBTrigger(
Expand All @@ -24,7 +29,6 @@ public static async Task Run(
LeaseCollectionPrefix = "moderator",
CreateLeaseCollectionIfNotExists = true)]IReadOnlyList<Document> input,
[Table("EmailList")] CloudTable cloudTable,
[SendGrid(ApiKey = "SendGridKey")] IAsyncCollector<SendGridMessage> messageCollector,
ILogger log)
{
if (input == null || input.Count == 0)
Expand Down Expand Up @@ -54,16 +58,18 @@ public static async Task Run(
return;
}

// TODO: make better email
string body = EmailTemplate.GetModeratorEmailBody(documentTimeStamp, location);

var timeConstraint = TimeLimiter.GetFromMaxCountByInterval(SendRate, TimeSpan.FromSeconds(1));
var aws = new AmazonSimpleEmailServiceClient(RegionEndpoint.USWest2);
log.LogInformation("Retrieving email list and sending notifications");
foreach (var emailEntity in EmailHelpers.GetEmailEntities(cloudTable, "Moderator"))
{
string emailSubject = string.Format("OrcaHello Candidate at location {0}", location);
await timeConstraint;
string emailSubject = string.Format("OrcaHello Candidate at location {0}", location);
var email = EmailHelpers.CreateEmail(Environment.GetEnvironmentVariable("SenderEmail"),
emailEntity.Email, emailSubject, body);
await messageCollector.AddAsync(email);
await aws.SendEmailAsync(email);
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions NotificationSystem/SendSubscriberEmail.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System;
using Amazon;
using Amazon.SimpleEmail;
using RateLimiter;
using ComposableAsync;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -10,20 +14,20 @@
using Newtonsoft.Json.Linq;
using NotificationSystem.Template;
using NotificationSystem.Utilities;
using SendGrid.Helpers.Mail;

namespace NotificationSystem
{
[StorageAccount("OrcaNotificationStorageSetting")]
public static class SendSubscriberEmail
{
static int SendRate = 14;

[FunctionName("SendSubscriberEmail")]
// TODO: change timer to once per hour (0 0 * * * *)
public static async Task Run(
[TimerTrigger("0 */1 * * * *")] TimerInfo myTimer,
[Queue("srkwfound")] CloudQueue cloudQueue,
[Table("EmailList")] CloudTable cloudTable,
[SendGrid(ApiKey = "SendGridKey")] IAsyncCollector<SendGridMessage> messageCollector,
ILogger log)
{
log.LogInformation("Checking if there are items in queue");
Expand All @@ -38,12 +42,15 @@ public static async Task Run(
log.LogInformation("Creating email message");
var body = await CreateBody(cloudQueue);

var timeConstraint = TimeLimiter.GetFromMaxCountByInterval(SendRate, TimeSpan.FromSeconds(1));
var aws = new AmazonSimpleEmailServiceClient(RegionEndpoint.USWest2);
log.LogInformation("Retrieving email list and sending notifications");
foreach (var emailEntity in EmailHelpers.GetEmailEntities(cloudTable, "Subscriber"))
{
await timeConstraint;
var email = EmailHelpers.CreateEmail(Environment.GetEnvironmentVariable("SenderEmail"),
emailEntity.Email, "Notification: Orca detected!", body);
await messageCollector.AddAsync(email);
await aws.SendEmailAsync(email);
}
}

Expand Down
24 changes: 16 additions & 8 deletions NotificationSystem/Utilities/EmailHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NotificationSystem.Models;
using SendGrid.Helpers.Mail;
using Amazon.SimpleEmail.Model;

namespace NotificationSystem.Utilities
{
Expand Down Expand Up @@ -72,14 +72,22 @@ public static IEnumerable<EmailEntity> GetEmailEntities(CloudTable cloudTable, s
return cloudTable.ExecuteQuery(query);
}

public static SendGridMessage CreateEmail(string from, string to, string subject, string body)
public static SendEmailRequest CreateEmail(string from, string to, string subject, string body)
{
var message = new SendGridMessage();
message.AddTo(to);
message.AddContent("text/html", body);
message.SetFrom(from);
message.SetSubject(subject);
return message;
var email = new SendEmailRequest();
email.Source = from;
email.Destination = new Destination(new List<string> { to });
//Create message and attach to email request.
Message message = new Message();
message.Subject = new Content(subject);
message.Body = new Body();
message.Body.Html = new Content
{
Charset = "UTF-8",
Data = body
};
email.Message = message;
return email;
}
}
}

0 comments on commit 133efb9

Please sign in to comment.