TIP
💡 Learn more : Azure Functions Documentation (opens new window).
# How to create an email subscription with Azure Functions - Storing Emails
# Overview
Full Source Code The source code for the app can be found on GitHub (opens new window)
This blog post is part of a series on how to generate a weekly digest email for a blog using Azure Functions, SendGrid and Azure Storage.
- Part 1 - What we're going to build and how to build it (opens new window)
- Part 2 - Storing Emails using Azure Table Storage (this post) (opens new window)
- Part 3 - Writing the Frontend with HTML5 and jQuery (opens new window)
- Part 4 - Sending Emails with Sendgrid and Azure Functions (opens new window)
We're trying to build a Email Subscription similar to the following. If you want to catch up, then read the previous post.
# Continuing where we left off
We recently created a Visual Studio project that used the Azure Functions template. We used NuGet to pull in references to the following packages that we'll be working with shortly:
- Azure.Data.Tables
To work with Azure Table Storage.
- Microsoft.WindowsAzure.ConfigurationManager
To hide our API keys
- Sendgrid
To send our emails
- System.ServiceModel.Syndication
To work with RSS feeds - use prerelease packages to find it
Return to the project we created yesterday and right-click the project and select Add Item and select Azure Functions. Now give it a name such as StoreEmail and select Http Trigger along with the defaults as shown below.
We only need this to be a post request, so modify the Run method's signature to match the following :
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
Keep in mind: You can use output bindings (opens new window) to provide a declarative way to connect to data from within your code vs using the code below. Thanks to Matt Honeycutt in the comments.
Since we'll be working with Azure Table Storage and I prefer to show you code that you can reuse anywhere, we need to setup a class that has a single field:
- EmailAddress - to store the email that the user typed in
We'll also supply the PartitionKey to be the same every time and use a Guid for our RowKey.
class EmailEntity : ITableEntity
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
public string EmailAddress { get; set; }
public EmailEntity(string email)
{
EmailAddress = email;
PartitionKey = "SendEmailToReaders";
RowKey = Guid.NewGuid().ToString();
}
public EmailEntity()
{
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
I also have a helper class that we'll use to store the data, so add the following which will allow us to pass a table object and a new email instance:
static void CreateMessage(TableClient table, EmailEntity newemail)
{
table.AddEntity(newemail);
}
2
3
4
Finally, we'll need add the code for the Run method:
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
//(Block #1)
var postData = await req.Content.ReadAsFormDataAsync();
var missingFields = new List<string>();
if (postData["fromEmail"] == null)
{
missingFields.Add("fromEmail");
}
if (missingFields.Any())
{
var missingFieldsSummary = String.Join(", ", missingFields);
return req.CreateResponse(HttpStatusCode.BadRequest, $"Missing field(s): {missingFieldsSummary}");
}
//(End Block #1)
//(Block #2)
try
{
// the line below can be hardcoded if you aren't using AppSettings
var serviceClient = new TableServiceClient(ConfigurationManager.AppSettings["TableStorageConnString"]);
TableClient table = serviceClient.GetTableClient("MCBlogSubscribers");
table.CreateIfNotExists();
CreateMessage(table, new EmailEntity(postData["fromEmail"]));
return req.CreateResponse(HttpStatusCode.OK, "Thanks! I've successfully received your request. "); //
}
catch (Exception ex)
{
return req.CreateResponse(HttpStatusCode.InternalServerError, new
{
status = false,
message = $"There are problems storing your email address: {ex.GetType()}"
});
}
//(End Block #2)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Keep in mind, you'll need to pull in your using references for the namespaces we added earlier.
Block #1 is all about pulling in the POST data and checking to see if an email address is being sent. If it is, then it will send a summary of what fields are missing.
Block #2 tries to save the input via the Azure Table Storage account that we created and if it saves successfully, then returns to the client everything went fine. Otherwise, output to the client what the problem was. Keep in mind, that I'm using ConfigurationManager and you can hardcode this value if you please.
Hit the Run button in Visual Studio and you'll see the following:
Make note of the localhost where it is running and use something like Postman to test your POST call.
In the gif below, I've configured Postman to my localhost URL and supplied an email address.
I can test the Azure Function by 1) Not supplying anything and 2) Supplying an email address. You'll see the error handling and success messages return to Postman.