Skip to content

Commit c42239c

Browse files
Implementation of the needed SendGridMessageBuilder to take incoming data and move it into a mail message.
1 parent 9c03b6b commit c42239c

File tree

5 files changed

+183
-14
lines changed

5 files changed

+183
-14
lines changed

src/NetCore.Utilities.Email.SendGrid.Tests/SmtpServiceTests.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ public class SendGridServiceTests
1515
AddEnvironmentSuffix = false,
1616
AlwaysTemplateEmails = false
1717
};
18+
19+
private Mock<ISendGridMessageBuilder> _sendGridMessageBuilderMock;
1820
private readonly ISendGridService _service;
1921

20-
public SendGridServiceTests()
22+
public SendGridServiceTests(Mock<ISendGridMessageBuilder> sendGridMessageBuilderMock)
2123
{
22-
_service = new SendGridService(new OptionsWrapper<SendGridServiceOptions>(_options));
24+
_sendGridMessageBuilderMock = sendGridMessageBuilderMock;
25+
_service = new SendGridService(new OptionsWrapper<SendGridServiceOptions>(_options),
26+
sendGridMessageBuilderMock.Object);
2327
}
2428

2529
[Fact]
@@ -39,7 +43,7 @@ public void AdminEmail_ShouldReturnConfigurationEmail()
3943
public void AdminEmail_ShouldReturnNullWhenNoConfiguration()
4044
{
4145
//Arrange
42-
var testService = new SendGridService(new OptionsWrapper<SendGridServiceOptions>(null));
46+
var testService = new SendGridService(new OptionsWrapper<SendGridServiceOptions>(null), _sendGridMessageBuilderMock.Object);
4347

4448
//Act
4549
var result = testService.AdminEmail;

src/NetCore.Utilities.Email.SendGrid/DependencyResolution/StartupExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static void UseIcgNetCoreUtilitiesEmailSendGrid(this IServiceCollection s
2020

2121
//Bind additional services
2222
services.AddTransient<ISendGridService, SendGridService>();
23+
services.AddTransient<ISendGridMessageBuilder, SendGridMessageBuilder>();
2324
services.Configure<SendGridServiceOptions>(configuration.GetSection(nameof(SendGridServiceOptions)));
2425
}
2526
}

src/NetCore.Utilities.Email.SendGrid/NetCore.Utilities.Email.SendGrid.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
<PrivateAssets>all</PrivateAssets>
4444
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4545
</PackageReference>
46+
<PackageReference Include="SendGrid" Version="9.24.0" />
4647
</ItemGroup>
4748

4849
</Project>
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.RegularExpressions;
4+
using Microsoft.Extensions.Hosting;
5+
using Microsoft.Extensions.Logging;
6+
using Microsoft.Extensions.Options;
7+
using SendGrid.Helpers.Mail;
8+
9+
namespace ICG.NetCore.Utilities.Email.SendGrid
10+
{
11+
/// <summary>
12+
/// The service takes an incoming request and build the proper SendGrid message structure for composing the messages
13+
/// </summary>
14+
public interface ISendGridMessageBuilder
15+
{
16+
/// <summary>
17+
/// Creates a simple message for sending
18+
/// </summary>
19+
/// <param name="from">Who the message is from</param>
20+
/// <param name="to">Who the message is to</param>
21+
/// <param name="subject">The subject of the message</param>
22+
/// <param name="bodyHtml">The Email's HTML content</param>
23+
/// <returns></returns>
24+
SendGridMessage CreateMessage(string from, string to, string subject, string bodyHtml);
25+
26+
/// <summary>
27+
/// Creates a simple message for sending with a custom template
28+
/// </summary>
29+
/// <param name="from">Who the message is from</param>
30+
/// <param name="to">Who the message is to</param>
31+
/// <param name="cc">An optional listing of CC addresses</param>
32+
/// <param name="subject">The subject of the message</param>
33+
/// <param name="bodyHtml">The Email's HTML content</param>
34+
/// <param name="templateName">The name of the template to use</param>
35+
/// <returns></returns>
36+
SendGridMessage CreateMessage(string from, string to, IEnumerable<string> cc, string subject, string bodyHtml,
37+
string templateName = "");
38+
39+
/// <summary>
40+
/// Creates a simple message for sending with a custom template and attachment
41+
/// </summary>
42+
/// <param name="from">Who the message is from</param>
43+
/// <param name="to">Who the message is to</param>
44+
/// <param name="cc">An optional listing of CC addresses</param>
45+
/// <param name="fileContent">The content of the attachment in bytes</param>
46+
/// <param name="fileName">The desired name for the file attachment</param>
47+
/// <param name="subject">The subject of the message</param>
48+
/// <param name="bodyHtml">The Email's HTML content</param>
49+
/// <param name="templateName">The name of the template to use</param>
50+
SendGridMessage CreateMessageWithAttachment(string from, string to, IEnumerable<string> cc,
51+
byte[] fileContent, string fileName, string subject, string bodyHtml, string templateName = "");
52+
}
53+
54+
/// <inheritdoc cref="ISendGridMessageBuilder"/>
55+
public class SendGridMessageBuilder : ISendGridMessageBuilder
56+
{
57+
private readonly IHostingEnvironment _hostingEnvironment;
58+
private readonly IEmailTemplateFactory _emailTemplateFactory;
59+
private readonly SendGridServiceOptions _serviceOptions;
60+
private readonly ILogger _logger;
61+
62+
/// <summary>
63+
/// Default constructor
64+
/// </summary>
65+
/// <param name="hostingEnvironment"></param>
66+
/// <param name="emailTemplateFactory"></param>
67+
/// <param name="options"></param>
68+
/// <param name="loggerFactory"></param>
69+
public SendGridMessageBuilder(IHostingEnvironment hostingEnvironment, IEmailTemplateFactory emailTemplateFactory,
70+
IOptions<SendGridServiceOptions> options, ILoggerFactory loggerFactory)
71+
{
72+
_hostingEnvironment = hostingEnvironment;
73+
_emailTemplateFactory = emailTemplateFactory;
74+
_serviceOptions = options.Value;
75+
_logger = loggerFactory.CreateLogger<SendGridMessageBuilder>();
76+
}
77+
78+
/// <inheritdoc />
79+
public SendGridMessage CreateMessage(string from, string to, string subject, string bodyHtml)
80+
{
81+
return CreateMessage(from, to, null, subject, bodyHtml);
82+
}
83+
84+
/// <inheritdoc />
85+
public SendGridMessage CreateMessage(string from, string to, IEnumerable<string> cc, string subject, string bodyHtml, string templateName = "")
86+
{
87+
//Validate inputs
88+
if (string.IsNullOrEmpty(from))
89+
throw new ArgumentNullException(nameof(from));
90+
if (string.IsNullOrEmpty(to))
91+
throw new ArgumentNullException(nameof(to));
92+
if (string.IsNullOrEmpty(subject))
93+
throw new ArgumentNullException(nameof(subject));
94+
if (string.IsNullOrEmpty(bodyHtml))
95+
throw new ArgumentNullException(nameof(bodyHtml));
96+
97+
//Get addresses
98+
var fromAddress = new EmailAddress(from);
99+
var recipients = new List<EmailAddress> {new EmailAddress(to)};
100+
if (cc != null)
101+
{
102+
foreach (var item in cc)
103+
{
104+
try
105+
{
106+
recipients.Add(new EmailAddress(item));
107+
}
108+
catch (Exception ex)
109+
{
110+
_logger.LogWarning(ex, $"Unable to add {item} to email copy list");
111+
}
112+
}
113+
}
114+
115+
//Handle subjects
116+
if (_serviceOptions.AddEnvironmentSuffix && !_hostingEnvironment.IsProduction())
117+
subject = $"{subject} ({_hostingEnvironment.EnvironmentName})";
118+
119+
//Perform templating
120+
if (_serviceOptions.AlwaysTemplateEmails && string.IsNullOrEmpty(templateName))
121+
bodyHtml = _emailTemplateFactory.BuildEmailContent(subject, bodyHtml);
122+
else if (!string.IsNullOrEmpty(templateName))
123+
bodyHtml = _emailTemplateFactory.BuildEmailContent(subject, bodyHtml,
124+
templateName: templateName);
125+
126+
//Get body text
127+
var plainTextBody = Regex.Replace(bodyHtml, "<[^>]*>", "");
128+
129+
//Build message
130+
if (recipients.Count == 1)
131+
return MailHelper.CreateSingleEmail(fromAddress, recipients[0], subject, plainTextBody, bodyHtml);
132+
133+
return MailHelper.CreateSingleEmailToMultipleRecipients(fromAddress, recipients, subject, plainTextBody,
134+
bodyHtml);
135+
}
136+
137+
public SendGridMessage CreateMessageWithAttachment(string from, string to, IEnumerable<string> cc,
138+
byte[] fileContent, string fileName, string subject, string bodyHtml, string templateName = "")
139+
{
140+
//Build the basic message
141+
var toSend = CreateMessage(from, to, cc, subject, bodyHtml, templateName);
142+
143+
//Attach file
144+
toSend.Attachments = new List<Attachment>
145+
{
146+
new Attachment
147+
{
148+
Content = Convert.ToBase64String(fileContent),
149+
Filename = fileName,
150+
Disposition = "attachment"
151+
}
152+
};
153+
return toSend;
154+
}
155+
156+
}
157+
}

src/NetCore.Utilities.Email.SendGrid/SendGridService.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public interface ISendGridService
4848
/// <param name="subject">The message subject</param>
4949
/// <param name="bodyHtml">The message body</param>
5050
/// <param name="templateName">The optional custom template to override with</param>
51-
void SendMessage(string toAddress, IEnumerable<string> ccAddressList, string subject, string bodyHtml, string templateName = "");
51+
/// <param name="customKey">The custom key for API usage if needed</param>
52+
void SendMessage(string toAddress, IEnumerable<string> ccAddressList, string subject, string bodyHtml, string templateName = "", string customKey = "");
5253

5354
/// <summary>
5455
/// Creates a message with an attachment
@@ -60,15 +61,17 @@ public interface ISendGridService
6061
/// <param name="fileName">Attachment file name</param>
6162
/// <param name="bodyHtml">The HTML body contents</param>
6263
/// <param name="templateName">The optional custom template to override with</param>
64+
/// <param name="customKey">The custom key for API usage if needed</param>
6365
/// <returns></returns>
6466
void SendMessageWithAttachment(string toAddress, IEnumerable<string> ccAddressList, string subject,
65-
byte[] fileContent, string fileName, string bodyHtml, string templateName = "");
67+
byte[] fileContent, string fileName, string bodyHtml, string templateName = "", string customKey = "");
6668
}
6769

6870
/// <inheritdoc />
6971
public class SendGridService : ISendGridService
7072
{
7173
private readonly SendGridServiceOptions _serviceOptions;
74+
private readonly ISendGridMessageBuilder _messageBuilder;
7275

7376
/// <inheritdoc />
7477
public string AdminEmail => _serviceOptions?.AdminEmail;
@@ -77,8 +80,9 @@ public class SendGridService : ISendGridService
7780
/// DI Capable Constructor for SendGrid message delivery using MimeKit/MailKit
7881
/// </summary>
7982
/// <param name="serviceOptions"></param>
80-
public SendGridService(IOptions<SendGridServiceOptions> serviceOptions)
83+
public SendGridService(IOptions<SendGridServiceOptions> serviceOptions, ISendGridMessageBuilder messageBuilder)
8184
{
85+
_messageBuilder = messageBuilder;
8286
_serviceOptions = serviceOptions.Value;
8387
}
8488

@@ -103,22 +107,24 @@ public void SendMessage(string toAddress, string subject, string bodyHtml)
103107
}
104108

105109
/// <inheritdoc />
106-
public void SendMessage(string toAddress, IEnumerable<string> ccAddressList, string subject, string bodyHtml, string templateName = "")
110+
public void SendMessage(string toAddress, IEnumerable<string> ccAddressList, string subject, string bodyHtml, string templateName = "", string customKey = "")
107111
{
108-
//Convert to a mime message
109-
//var toSend = _mimeMessageFactory.CreateFromMessage(_serviceOptions.AdminEmail, toAddress,
110-
// ccAddressList, subject, bodyHtml, templateName);
112+
//Get the message to send
113+
var toSend = _messageBuilder.CreateMessage(_serviceOptions.AdminEmail, toAddress, ccAddressList, subject,
114+
bodyHtml, templateName);
115+
116+
111117

112118
////Send
113119
//_mimeKitService.SendEmail(toSend);
114120
}
115121

116122
/// <inheritdoc />
117-
public void SendMessageWithAttachment(string toAddress, IEnumerable<string> ccAddressList, string subject, byte[] fileContent, string fileName, string bodyHtml, string templateName = "")
123+
public void SendMessageWithAttachment(string toAddress, IEnumerable<string> ccAddressList, string subject, byte[] fileContent, string fileName, string bodyHtml, string templateName = "", string customKey = "")
118124
{
119-
////Covert to a mime message
120-
//var toSend = _mimeMessageFactory.CreateFromMessageWithAttachment(_serviceOptions.AdminEmail, toAddress,
121-
// ccAddressList, subject, fileContent, fileName, bodyHtml, templateName);
125+
//Get the message to send
126+
var toSend = _messageBuilder.CreateMessageWithAttachment(_serviceOptions.AdminEmail, toAddress,
127+
ccAddressList, fileContent, fileName, subject, bodyHtml, templateName);
122128

123129
////Send
124130
//_mimeKitService.SendEmail(toSend);

0 commit comments

Comments
 (0)