-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bss.Platform.Notifications.Smtp - redirect notifications to test emai…
…l if not production environment (#13) * Bss.Platform.Notifications.Smtp - redirect notifications to test email if not production environment * prettify readme * refactoring * actualize readme * actualize readme * actualize readme * actualize readme * actualize readme * actualize readme * actualize readme --------- Co-authored-by: Khaperskaia, Anna <[email protected]> Co-authored-by: Artem Leshchev <[email protected]>
- Loading branch information
1 parent
dd6d30b
commit a47c471
Showing
14 changed files
with
343 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ This repository offers a wide collection of .NET packages for use in microservic | |
- [Kubernetes Insights](#Insights) | ||
- [Kubernetes Health Checks](#Health-Checks) | ||
- [NHibernate](#NHibernate) | ||
- [Notifications](#Notifications) | ||
|
||
## RabbitMQ | ||
|
||
|
@@ -272,3 +273,50 @@ To mock IQueryable, in your code, call: | |
var entity = new Entity(); | ||
repository.GetQueryable().Returns(new TestQueryable<Entity>(entity)); | ||
``` | ||
|
||
## Notifications | ||
|
||
To use platform senders for notifications, first install the [NuGet package](https://www.nuget.org/packages/Luxoft.Bss.Platform.Notifications): | ||
```shell | ||
dotnet add package Luxoft.Bss.Platform.Notifications | ||
``` | ||
|
||
Then register notifications service in DI | ||
```C# | ||
services | ||
.AddPlatformNotifications(builder.Environment, builder.Configuration) | ||
``` | ||
|
||
Then fill configuration settings: | ||
```json | ||
{ | ||
"NotificationSender": { | ||
"Server": "smtp.server.com", -- smtp server host | ||
"RedirectTo": ["[email protected]"] -- this address will be used as single recipient for all messages on non-prod environments | ||
} | ||
} | ||
``` | ||
|
||
Now you can send messages to smtp server: | ||
```C# | ||
public class YourNotificationRequestHandler(IEmailSender sender) : IRequestHandler<YourNotificationRequest> | ||
{ | ||
public async Task Handle(YourNotificationRequest request, CancellationToken cancellationToken) | ||
{ | ||
var attachment = new Attachment(new MemoryStream(), request.AttachmentName); | ||
attachment.ContentDisposition!.Inline = true; | ||
|
||
var message = new EmailModel( | ||
request.Subject, | ||
request.Body, | ||
new MailAddress(request.From), | ||
new[] { new MailAddress(request.To) }, | ||
Attachments: new[] { attachment }); | ||
|
||
await sender.SendAsync(message, token); | ||
} | ||
} | ||
``` | ||
|
||
> [!NOTE] | ||
> Note that attachment will be inlined only if its 'Inline' field is true and its name is referred as image source in message body. |
9 changes: 9 additions & 0 deletions
9
src/Bss.Platform.Notifications/Bss.Platform.Notifications.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<PackageId>Luxoft.Bss.Platform.Notifications</PackageId> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions"/> | ||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions"/> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using Bss.Platform.Notifications.Interfaces; | ||
using Bss.Platform.Notifications.Models; | ||
using Bss.Platform.Notifications.Services; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace Bss.Platform.Notifications; | ||
|
||
public static class DependencyInjection | ||
{ | ||
public static IServiceCollection AddPlatformNotifications( | ||
this IServiceCollection services, | ||
IHostEnvironment hostEnvironment, | ||
IConfiguration configuration) | ||
{ | ||
var settings = configuration.GetSection(NotificationSenderOptions.SectionName).Get<NotificationSenderOptions>()!; | ||
|
||
return AddTestEnvironmentRedirection(services, hostEnvironment, settings) | ||
.AddMailMessageSenders(settings) | ||
.Configure<NotificationSenderOptions>(configuration.GetSection(NotificationSenderOptions.SectionName)) | ||
.AddScoped<IEmailSender, EmailSender>(); | ||
} | ||
|
||
private static IServiceCollection AddTestEnvironmentRedirection( | ||
this IServiceCollection services, | ||
IHostEnvironment hostEnvironment, | ||
NotificationSenderOptions settings) | ||
{ | ||
if (hostEnvironment.IsProduction()) | ||
{ | ||
return services; | ||
} | ||
|
||
if (settings.RedirectTo?.Length == 0) | ||
{ | ||
throw new ArgumentException("Test email address is not provided"); | ||
} | ||
|
||
return services.AddScoped<IRedirectService, RedirectService>(); | ||
} | ||
|
||
private static IServiceCollection AddMailMessageSenders(this IServiceCollection services, NotificationSenderOptions settings) | ||
{ | ||
if (settings.IsSmtpEnabled) | ||
{ | ||
services.AddScoped<IMailMessageSender, SmtpSender>(); | ||
} | ||
|
||
if (!string.IsNullOrWhiteSpace(settings.OutputFolder)) | ||
{ | ||
services.AddScoped<IMailMessageSender, FileSender>(); | ||
} | ||
|
||
return services; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System.Net.Mail; | ||
|
||
using Bss.Platform.Notifications.Models; | ||
|
||
namespace Bss.Platform.Notifications.Interfaces; | ||
|
||
public interface IEmailSender | ||
{ | ||
Task<MailMessage> SendAsync(EmailModel model, CancellationToken token); | ||
} |
8 changes: 8 additions & 0 deletions
8
src/Bss.Platform.Notifications/Interfaces/IMailMessageSender.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.Net.Mail; | ||
|
||
namespace Bss.Platform.Notifications.Interfaces; | ||
|
||
public interface IMailMessageSender | ||
{ | ||
Task SendAsync(MailMessage message, CancellationToken token); | ||
} |
8 changes: 8 additions & 0 deletions
8
src/Bss.Platform.Notifications/Interfaces/IRedirectService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.Net.Mail; | ||
|
||
namespace Bss.Platform.Notifications.Interfaces; | ||
|
||
public interface IRedirectService | ||
{ | ||
void Redirect(MailMessage message); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Net.Mail; | ||
|
||
namespace Bss.Platform.Notifications.Models; | ||
|
||
public record EmailModel( | ||
string Subject, | ||
string Body, | ||
MailAddress From, | ||
MailAddress[] To, | ||
MailAddress[]? Cc = null, | ||
MailAddress[]? ReplyTo = null, | ||
Attachment[]? Attachments = null); |
16 changes: 16 additions & 0 deletions
16
src/Bss.Platform.Notifications/Models/NotificationSenderOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Bss.Platform.Notifications.Models; | ||
|
||
public class NotificationSenderOptions | ||
{ | ||
public const string SectionName = "NotificationSender"; | ||
|
||
public bool IsSmtpEnabled { get; set; } = true; | ||
|
||
public string? OutputFolder { get; set; } | ||
|
||
public string Server { get; set; } = default!; | ||
|
||
public int Port { get; set; } = 25; | ||
|
||
public string[]? RedirectTo { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Net.Mail; | ||
using System.Text.RegularExpressions; | ||
|
||
using Bss.Platform.Notifications.Interfaces; | ||
using Bss.Platform.Notifications.Models; | ||
|
||
namespace Bss.Platform.Notifications.Services; | ||
|
||
internal class EmailSender(IEnumerable<IMailMessageSender> senders, IRedirectService? redirectService = null) : IEmailSender | ||
{ | ||
public async Task<MailMessage> SendAsync(EmailModel model, CancellationToken token) | ||
{ | ||
var message = Convert(model); | ||
|
||
redirectService?.Redirect(message); | ||
|
||
foreach (var sender in senders) | ||
{ | ||
await sender.SendAsync(message, token); | ||
} | ||
|
||
return message; | ||
} | ||
|
||
private static MailMessage Convert(EmailModel model) | ||
{ | ||
var mailMessage = new MailMessage { Subject = model.Subject, Body = model.Body, From = model.From, IsBodyHtml = true }; | ||
|
||
AddRange(mailMessage.To, model.To); | ||
|
||
if (model.Cc?.Length > 0) | ||
{ | ||
AddRange(mailMessage.CC, model.Cc); | ||
} | ||
|
||
if (model.ReplyTo?.Length > 0) | ||
{ | ||
AddRange(mailMessage.ReplyToList, model.ReplyTo); | ||
} | ||
|
||
if (model.Attachments?.Length > 0) | ||
{ | ||
SetAttachments(model.Attachments, mailMessage); | ||
} | ||
|
||
return mailMessage; | ||
} | ||
|
||
private static void SetAttachments(Attachment[] attachments, MailMessage mailMessage) | ||
{ | ||
foreach (var attachment in attachments) | ||
{ | ||
mailMessage.Attachments.Add(attachment); | ||
if (!attachment.ContentDisposition!.Inline) | ||
{ | ||
continue; | ||
} | ||
|
||
var srcRegex = $"src\\s*=\\s*\"{attachment.Name}\""; | ||
if (!Regex.IsMatch(mailMessage.Body, srcRegex, RegexOptions.IgnoreCase)) | ||
{ | ||
continue; | ||
} | ||
|
||
mailMessage.Body = Regex.Replace(mailMessage.Body, srcRegex, $"src=\"cid:{attachment.ContentId}\"", RegexOptions.IgnoreCase); | ||
} | ||
} | ||
|
||
private static void AddRange(MailAddressCollection collection, IEnumerable<MailAddress> addresses) | ||
{ | ||
foreach (var address in addresses) | ||
{ | ||
collection.Add(address); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Net.Mail; | ||
|
||
using Bss.Platform.Notifications.Interfaces; | ||
using Bss.Platform.Notifications.Models; | ||
|
||
using Microsoft.Extensions.Options; | ||
|
||
namespace Bss.Platform.Notifications.Services; | ||
|
||
internal class FileSender(IOptions<NotificationSenderOptions> settings) : IMailMessageSender | ||
{ | ||
public async Task SendAsync(MailMessage message, CancellationToken token) | ||
{ | ||
using var client = this.GetSmtpClient(); | ||
await client.SendMailAsync(message, token); | ||
} | ||
|
||
private SmtpClient GetSmtpClient() => | ||
new() | ||
{ | ||
UseDefaultCredentials = true, | ||
DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory, | ||
PickupDirectoryLocation = settings.Value.OutputFolder | ||
}; | ||
} |
42 changes: 42 additions & 0 deletions
42
src/Bss.Platform.Notifications/Services/RedirectService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System.Net.Mail; | ||
|
||
using Bss.Platform.Notifications.Interfaces; | ||
using Bss.Platform.Notifications.Models; | ||
|
||
using Microsoft.Extensions.Options; | ||
|
||
namespace Bss.Platform.Notifications.Services; | ||
|
||
internal class RedirectService(IOptions<NotificationSenderOptions> settings) : IRedirectService | ||
{ | ||
public void Redirect(MailMessage message) | ||
{ | ||
AddRecipientsToBody(message); | ||
|
||
ClearRecipients(message); | ||
|
||
foreach (var address in settings.Value.RedirectTo!.Select(z => z.Trim()).Distinct().Select(z => new MailAddress(z))) | ||
{ | ||
message.To.Add(address); | ||
} | ||
} | ||
|
||
private static void ClearRecipients(MailMessage message) | ||
{ | ||
message.To.Clear(); | ||
message.CC.Clear(); | ||
message.Bcc.Clear(); | ||
message.ReplyToList.Clear(); | ||
} | ||
|
||
private static void AddRecipientsToBody(MailMessage message) | ||
{ | ||
var originalRecipients = | ||
$"From: {message.From!.Address}<br>" | ||
+ $"To: {string.Join("; ", message.To.Select(x => x.Address))}<br>" | ||
+ $"CC: {string.Join("; ", message.CC.Select(x => x.Address))}<br>" | ||
+ $"Reply To: {string.Join("; ", message.ReplyToList.Select(x => x.Address))}<br><br>"; | ||
|
||
message.Body = $"{originalRecipients}{message.Body}"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.Net.Mail; | ||
|
||
using Bss.Platform.Notifications.Interfaces; | ||
using Bss.Platform.Notifications.Models; | ||
|
||
using Microsoft.Extensions.Options; | ||
|
||
namespace Bss.Platform.Notifications.Services; | ||
|
||
internal class SmtpSender(IOptions<NotificationSenderOptions> settings) : IMailMessageSender | ||
{ | ||
public async Task SendAsync(MailMessage message, CancellationToken token) | ||
{ | ||
using var client = this.GetSmtpClient(); | ||
await client.SendMailAsync(message, token); | ||
} | ||
|
||
private SmtpClient GetSmtpClient() => new(settings.Value.Server, settings.Value.Port) { UseDefaultCredentials = true }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters