Skip to content

Commit

Permalink
feature(#59): Added decorator to allow global BCC address in all emails
Browse files Browse the repository at this point in the history
  • Loading branch information
jhartmann123 authored and davidroth committed Sep 10, 2024
1 parent 0c458f2 commit c17f430
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/Email/src/ContainerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ public static class ContainerExtensions
/// <summary>
/// Registers the components for sending emails.
///
/// Note: You need to register ViewLocalization in your services.
/// Note: You need to register ViewLocalization as well as the HtmlRenderer in your services.
/// Example:
/// <code>
/// services.AddScoped{HtmlRenderer}();
/// services.AddLocalization(options => options.ResourcesPath = "Resources/Localization");
///
/// services.AddMvc(options => options.Filters.Add(typeof(ExceptionFilter)))
Expand Down Expand Up @@ -48,5 +49,11 @@ public static void RegisterEmail(this Container container, Action<EmailOptions>
container.Collection.Append<IEmailAttachmentResolver, FileAttachmentResolver>(Lifestyle.Singleton);

container.Register(typeof(IRequestHandler<,>), Assembly.GetExecutingAssembly());

if (!string.IsNullOrWhiteSpace(options.BccAddress))
{
container.RegisterInstance(new SendEmailBccDecorator.Options(options.BccAddress));
container.RegisterDecorator<IRequestHandler<SendEmail, Unit>, SendEmailBccDecorator>();
}
}
}
}
3 changes: 3 additions & 0 deletions src/Email/src/EmailOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public class EmailOptions
/// <summary> Name of the sender. </summary>
public string? SenderName { get; set; }

/// <summary> A fixed BCC address which will be set in every email. If another BCC address is set for a specific email, the address of the email has precedence. </summary>
public string? BccAddress { get; set; }

/// <summary> Enable SSL connection to the mail server. Default is true. </summary>
public bool EnableSsl { get; set; } = true;

Expand Down
24 changes: 24 additions & 0 deletions src/Email/src/SendEmailBccDecorator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Fusonic GmbH. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license information.

using Fusonic.Extensions.Mediator;

namespace Fusonic.Extensions.Email;

public class SendEmailBccDecorator(IRequestHandler<SendEmail, Unit> innerHandler, SendEmailBccDecorator.Options options) : IRequestHandler<SendEmail, Unit>
{
public record Options(string BccAddress);

public Task<Unit> Handle(SendEmail request, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(request.BccRecipient))
{
request = request with
{
BccRecipient = options.BccAddress
};
}

return innerHandler.Handle(request, cancellationToken);
}
}
76 changes: 76 additions & 0 deletions src/Email/test/SendEmailBccDecoratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Fusonic GmbH. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license information.

using System.Globalization;
using FluentAssertions;
using Fusonic.Extensions.Email.Tests.Models;
using netDumbster.smtp;
using SimpleInjector;
using Xunit;

namespace Fusonic.Extensions.Email.Tests;

public class SendEmailBccDecoratorTests(SendEmailBccDecoratorTests.SendEmailBccDecoratorTestsFixture fixture) : TestBase<SendEmailBccDecoratorTests.SendEmailBccDecoratorTestsFixture>(fixture)
{
[Fact]
public async Task SendEmail_NoBccDefined_SetsConfiguredBccAddress()
{
Fixture.SmtpServer!.ClearReceivedEmail();

var model = new SendEmailTestEmailViewModel { SomeField = "Some field." };
await SendAsync(new SendEmail("[email protected]", "The Recipient", new CultureInfo("de-AT"), model));

Fixture.SmtpServer.ReceivedEmailCount.Should().Be(1);
var email = Fixture.SmtpServer.ReceivedEmail.Single();
email.ToAddresses
.Should()
.HaveCount(2)
.And.Contain(a => a.Address == "[email protected]")
.And.Contain(a => a.Address == "[email protected]");
}

[Fact]
public async Task SendEmail_BccDefined_ConfiguredBccAddressDoesNotOverwrite()
{
Fixture.SmtpServer!.ClearReceivedEmail();

var model = new SendEmailTestEmailViewModel { SomeField = "Some field." };
await SendAsync(new SendEmail("[email protected]", "The Recipient", new CultureInfo("de-AT"), model, BccRecipient: "[email protected]"));

Fixture.SmtpServer.ReceivedEmailCount.Should().Be(1);
var email = Fixture.SmtpServer.ReceivedEmail.Single();
email.ToAddresses
.Should()
.HaveCount(2)
.And.Contain(a => a.Address == "[email protected]")
.And.Contain(a => a.Address == "[email protected]");
}

public class SendEmailBccDecoratorTestsFixture : TestFixture
{
public SimpleSmtpServer? SmtpServer { get; private set; }

protected override void RegisterDependencies(Container container)
{
base.RegisterDependencies(container);

SmtpServer = SimpleSmtpServer.Start();

container.RegisterEmail(c =>
{
c.CssPath = "email.css";
c.SmtpServer = "localhost";
c.SmtpPort = SmtpServer.Configuration.Port;
c.SenderAddress = "[email protected]";
c.SenderName = "Test Fusonic";
c.BccAddress = "[email protected]";
});
}

public override async ValueTask DisposeAsync()
{
SmtpServer?.Dispose();
await base.DisposeAsync();
}
}
}

0 comments on commit c17f430

Please sign in to comment.