diff --git a/AllReady.Processing/AllReady.Processing.Tests/AllReady.Processing.Tests.csproj b/AllReady.Processing/AllReady.Processing.Tests/AllReady.Processing.Tests.csproj
new file mode 100644
index 0000000..b9525ef
--- /dev/null
+++ b/AllReady.Processing/AllReady.Processing.Tests/AllReady.Processing.Tests.csproj
@@ -0,0 +1,43 @@
+
+
+
+ net461
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AllReady.Processing/AllReady.Processing.Tests/ProcessEmailQueueMessageTests.cs b/AllReady.Processing/AllReady.Processing.Tests/ProcessEmailQueueMessageTests.cs
new file mode 100644
index 0000000..8b17f24
--- /dev/null
+++ b/AllReady.Processing/AllReady.Processing.Tests/ProcessEmailQueueMessageTests.cs
@@ -0,0 +1,120 @@
+using Moq;
+using Xunit;
+using Shouldly;
+using Microsoft.Azure.WebJobs.Host;
+using SendGrid.Helpers.Mail;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System;
+
+namespace AllReady.Processing.Tests
+{
+ public class ProcessEmailQueueMessageTests
+ {
+ // comes from Environment Variable
+ const string EmailSentFrom = "from@tests.com";
+ const string FromEnvironmentVariable = "Authentication:SendGrid:FromEmail";
+
+ [Fact]
+ public void ShouldOutputMailWithPlainTextOnly()
+ {
+ // Arrange
+ var loggerMock = new MockTrace();
+ var messageInQueue = MessageInQueue("Subject test", "test@testing.com", "Message text plain");
+ Environment.SetEnvironmentVariable(FromEnvironmentVariable, EmailSentFrom);
+ // Act
+ ProcessEmailQueueMessage.Run(messageInQueue, out Mail message, loggerMock);
+ // Assert
+ message.From.Name.ShouldBe("AllReady");
+ message.From.Address.ShouldBe(EmailSentFrom);
+ message.Subject.ShouldBe("Subject test");
+ message.Contents[0].Type.ShouldBe("text/plain");
+ message.Contents[0].Value.ShouldBe("Message text plain");
+ message.Personalization[0].Tos[0].Address.ShouldBe("test@testing.com");
+ }
+
+ [Fact]
+ public void ShouldOutputMailWithHtmlTextOnly()
+ {
+ // Arrange
+ var loggerMock = new MockTrace();
+ var messageInQueue = MessageInQueue("Subject test", "test@testing.com", null, "text");
+ //Environment.SetEnvironmentVariable(FromEnvironmentVariable, EmailSentFrom);
+ // Act
+ ProcessEmailQueueMessage.Run(messageInQueue, out Mail message, loggerMock);
+ // Assert
+ message.From.Name.ShouldBe("AllReady");
+ message.From.Address.ShouldBe(EmailSentFrom);
+ message.Subject.ShouldBe("Subject test");
+ message.Contents[0].Type.ShouldBe("text/html");
+ message.Contents[0].Value.ShouldBe("text");
+ message.Personalization[0].Tos[0].Address.ShouldBe("test@testing.com");
+ }
+
+ [Fact]
+ public void ShouldTraceTheSubjectAndRecepient()
+ {
+ // Arrange
+ var loggerMock = new MockTrace();
+ var messageInQueue = MessageInQueue("Subject test", "test@testing.com", null, "text");
+ Environment.SetEnvironmentVariable(FromEnvironmentVariable, EmailSentFrom);
+ // Act
+ ProcessEmailQueueMessage.Run(messageInQueue, out Mail message, loggerMock);
+ // Assert
+ loggerMock.Events.Count.ShouldBe(1);
+ loggerMock.Events[0].Level.ShouldBe(TraceLevel.Info);
+ loggerMock.Events[0].Message.ShouldBe("Sending email with subject `Subject test` to `test@testing.com`");
+ }
+
+ [Fact]
+ public void ShouldThrowOnDeserialization()
+ {
+ // Arrange
+ var loggerMock = new MockTrace();
+ Environment.SetEnvironmentVariable(FromEnvironmentVariable, EmailSentFrom);
+ // Act
+ // Assert
+ Should.Throw(() => ProcessEmailQueueMessage.Run("invalid message", out Mail message, loggerMock));
+ }
+
+ [Fact]
+ public void ShouldThrowForMissing_From()
+ {
+ // Arrange
+ var loggerMock = new MockTrace();
+ Environment.SetEnvironmentVariable(FromEnvironmentVariable, null);
+ var messageInQueue = MessageInQueue("Subject test", "test@testing.com", null, "text");
+
+ // Act
+ // Assert
+ Should.Throw(() => ProcessEmailQueueMessage.Run(messageInQueue, out Mail message, loggerMock));
+ }
+
+ public class MockTrace : TraceWriter
+ {
+ public List Events = new List();
+
+ public MockTrace() : base(TraceLevel.Verbose)
+ {
+ }
+
+ public override void Trace(TraceEvent traceEvent)
+ {
+ this.Events.Add(traceEvent);
+ }
+ }
+
+ private string MessageInQueue(string subject, string recipient, string message = null, string htmlMessage = null)
+ {
+ return $"{{" +
+ $"\"Recipient\":\"{recipient}\"," +
+ $"\"Subject\":\"{subject}\"," +
+ (message != null ? "\"Message\":\"" + message + "\"" : "") +
+ (htmlMessage!= null ? "\"HtmlMessage\":\"" + htmlMessage + "\"" : "") +
+ $"}}";
+ }
+
+ }
+}
+
+
diff --git a/AllReady.Processing/AllReady.Processing.sln b/AllReady.Processing/AllReady.Processing.sln
index b664a56..63b94f6 100644
--- a/AllReady.Processing/AllReady.Processing.sln
+++ b/AllReady.Processing/AllReady.Processing.sln
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AllReady.Processing", "AllReady.Processing\AllReady.Processing.csproj", "{C619B518-08A3-4CFC-BC22-CB0B4A63CB31}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllReady.Processing", "AllReady.Processing\AllReady.Processing.csproj", "{C619B518-08A3-4CFC-BC22-CB0B4A63CB31}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllReady.Processing.Tests", "AllReady.Processing.Tests\AllReady.Processing.Tests.csproj", "{1FDEA4EB-E405-44B3-81B1-05F2B5AEB034}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
{C619B518-08A3-4CFC-BC22-CB0B4A63CB31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C619B518-08A3-4CFC-BC22-CB0B4A63CB31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C619B518-08A3-4CFC-BC22-CB0B4A63CB31}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1FDEA4EB-E405-44B3-81B1-05F2B5AEB034}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1FDEA4EB-E405-44B3-81B1-05F2B5AEB034}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1FDEA4EB-E405-44B3-81B1-05F2B5AEB034}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1FDEA4EB-E405-44B3-81B1-05F2B5AEB034}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AllReady.Processing/AllReady.Processing/AllReady.Processing.csproj b/AllReady.Processing/AllReady.Processing/AllReady.Processing.csproj
index 0715787..0cc3591 100644
--- a/AllReady.Processing/AllReady.Processing/AllReady.Processing.csproj
+++ b/AllReady.Processing/AllReady.Processing/AllReady.Processing.csproj
@@ -3,7 +3,9 @@
net461
+
+
diff --git a/AllReady.Processing/AllReady.Processing/ProcessEmailQueueMessage.cs b/AllReady.Processing/AllReady.Processing/ProcessEmailQueueMessage.cs
new file mode 100644
index 0000000..7748dc4
--- /dev/null
+++ b/AllReady.Processing/AllReady.Processing/ProcessEmailQueueMessage.cs
@@ -0,0 +1,64 @@
+using System;
+using Microsoft.Azure.WebJobs;
+using Microsoft.Azure.WebJobs.Host;
+using Newtonsoft.Json;
+using SendGrid.Helpers.Mail;
+
+namespace AllReady.Processing
+{
+ public static class ProcessEmailQueueMessage
+ {
+ [FunctionName("ProcessEmailQueueMessage")]
+ [StorageAccount("AzureWebJobsStorage")]
+ public static void Run([QueueTrigger("email-pending-deliveries")] string queueItem,
+ [SendGrid(ApiKey = "AzureWebJobsSendGridApiKey")] out Mail message, TraceWriter log)
+ {
+ var queuedEmailMessage = JsonConvert.DeserializeObject(queueItem);
+
+ var from = GuardAgainstInvalidEmailAddress(
+ Environment.GetEnvironmentVariable("Authentication:SendGrid:FromEmail"));
+
+ log.Info($"Sending email with subject `{queuedEmailMessage.Subject}` to `{queuedEmailMessage.Recipient}`");
+
+ message = new Mail
+ {
+ From = new Email(from, "AllReady"),
+ Subject = queuedEmailMessage.Subject
+ };
+
+ if (queuedEmailMessage.Message != null)
+ {
+ message.AddContent(new Content
+ {
+ Type = "text/plain",
+ Value = queuedEmailMessage.Message
+ });
+ }
+
+ if (queuedEmailMessage.HtmlMessage != null)
+ {
+ message.AddContent(new Content
+ {
+ Type = "text/html",
+ Value = queuedEmailMessage.HtmlMessage
+ });
+ }
+
+ var personalization = new Personalization();
+ personalization.AddTo(new Email(queuedEmailMessage.Recipient));
+ message.AddPersonalization(personalization);
+ }
+
+ private static string GuardAgainstInvalidEmailAddress(string @from)
+ {
+ if (string.IsNullOrWhiteSpace(@from))
+ {
+ throw new InvalidOperationException(
+ "Environment variable `Authentication:SendGrid:FromEmail` is missing or contains invalid entry.");
+ }
+
+ return @from;
+ }
+ }
+}
+
diff --git a/AllReady.Processing/AllReady.Processing/QueueTest.cs b/AllReady.Processing/AllReady.Processing/QueueTest.cs
index dac8cde..f47a142 100644
--- a/AllReady.Processing/AllReady.Processing/QueueTest.cs
+++ b/AllReady.Processing/AllReady.Processing/QueueTest.cs
@@ -9,10 +9,10 @@ public static class QueueTest
// This function can be used locally to test interaction with your
// local storage emulator.
- [FunctionName("QueueTest")]
- public static void Run([QueueTrigger("queue-test", Connection = "")]string item, TraceWriter log)
- {
- log.Info($"A message was dequeued from the queue-test queue: {item}");
- }
+ //[FunctionName("QueueTest")]
+ //public static void Run([QueueTrigger("queue-test")]string item, TraceWriter log)
+ //{
+ // log.Info($"A message was dequeued from the queue-test queue: {item}");
+ //}
}
}
diff --git a/AllReady.Processing/AllReady.Processing/QueuedEmailMessage.cs b/AllReady.Processing/AllReady.Processing/QueuedEmailMessage.cs
new file mode 100644
index 0000000..6ff09f7
--- /dev/null
+++ b/AllReady.Processing/AllReady.Processing/QueuedEmailMessage.cs
@@ -0,0 +1,15 @@
+namespace AllReady.Processing
+{
+
+ public class QueuedEmailMessage
+ {
+
+ public string Recipient { get; set; }
+
+ public string Message { get; set; }
+
+ public string HtmlMessage { get; set; }
+
+ public string Subject { get; set; }
+ }
+}