Refactor email account configuration for multi-account support
Refactored `EmailAccountDto` to represent a single account with immutable properties and added an `Id` field. Introduced `EmailAccountsOptions` to manage multiple accounts and bound it to the `EmailAccounts` configuration section. Updated `DependencyInjection` to register `EmailAccountsOptions` and removed the old single-account binding. Refactored `LimilabsEmailService` to use `EmailAccountsOptions` and select the appropriate account dynamically. Replaced the `EmailAccount` section in `appsettings.Secrets.json` with a new `EmailAccounts` section supporting multiple accounts. Added a package reference for `Microsoft.Extensions.Options. ConfigurationExtensions` to support the options pattern.
This commit is contained in:
@@ -1,21 +1,27 @@
|
|||||||
namespace DigitalData.MessagingService.Application.Common.Dtos;
|
namespace DigitalData.MessagingService.Application.Common.Dtos;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO for EmailAccount query results.
|
/// DTO for a single email account configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EmailAccountDto
|
public class EmailAccountDto
|
||||||
{
|
{
|
||||||
public string Username { get; set; } = null!;
|
/// <summary>
|
||||||
|
/// Logical name to identify this account (e.g. "default", "support").
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; init; }
|
||||||
|
|
||||||
public string Password { get; set; } = null!;
|
public required string Username { get; init; }
|
||||||
|
|
||||||
public bool PasswordEncrypted { get; set; } = false;
|
public required string Password { get; init; }
|
||||||
|
|
||||||
public string SmtpServer { get; set; } = null!;
|
public bool PasswordEncrypted { get; init; } = false;
|
||||||
|
|
||||||
public int SmtpPort { get; set; }
|
public required string SmtpServer { get; init; }
|
||||||
|
|
||||||
public bool SmtpUseSsl { get; set; }
|
public int SmtpPort { get; init; }
|
||||||
|
|
||||||
public bool UseOAuth2 { get; set; }
|
public bool SmtpUseSsl { get; init; }
|
||||||
|
|
||||||
|
public bool UseOAuth2 { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using DigitalData.MessagingService.Application.Common.Dtos;
|
||||||
|
|
||||||
|
namespace DigitalData.MessagingService.Application.Common.Options;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper options class that holds a list of <see cref="EmailAccountDto"/> entries
|
||||||
|
/// bound from the <c>EmailAccounts</c> configuration section.
|
||||||
|
/// </summary>
|
||||||
|
public class EmailAccountsOptions
|
||||||
|
{
|
||||||
|
public const string SectionName = "EmailAccounts";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of configured email accounts.
|
||||||
|
/// </summary>
|
||||||
|
public required IEnumerable<EmailAccountDto> Accounts { get; init; } = [];
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Reflection;
|
using DigitalData.MessagingService.Application.Common.Options;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Application;
|
namespace DigitalData.MessagingService.Application;
|
||||||
|
|
||||||
@@ -35,6 +37,9 @@ public static class DependencyInjection
|
|||||||
// FluentValidation - Register all validators
|
// FluentValidation - Register all validators
|
||||||
services.AddValidatorsFromAssembly(assembly);
|
services.AddValidatorsFromAssembly(assembly);
|
||||||
|
|
||||||
|
// Register EmailAccounts configuration (IOptions<EmailAccountsOptions>)
|
||||||
|
services.Configure<EmailAccountsOptions>(configuration.GetSection(EmailAccountsOptions.SectionName));
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<PackageReference Include="MediatR" Version="14.2.0" />
|
<PackageReference Include="MediatR" Version="14.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.10" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -6,20 +6,21 @@ using Limilabs.Client.SMTP;
|
|||||||
using Limilabs.Mail;
|
using Limilabs.Mail;
|
||||||
using Limilabs.Mail.Headers;
|
using Limilabs.Mail.Headers;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using DigitalData.MessagingService.Application.Common.Options;
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Infrastructure.Services;
|
namespace DigitalData.MessagingService.Infrastructure.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Email service using Limilabs Mail.dll for SMTP operations (send-only).
|
/// Email service using Limilabs Mail.dll for SMTP operations (send-only).
|
||||||
/// Commercial-grade library with superior Exchange support.
|
/// Commercial-grade library with superior Exchange support.
|
||||||
/// SMTP configuration is injected via IOptions<EmailAccountDto> from appsettings.json.
|
/// SMTP configuration is injected via IOptions<EmailAccountsOptions> from appsettings.json.
|
||||||
|
/// Uses the first account in the list whose <see cref="EmailAccountDto.Name"/> equals <c>"default"</c>,
|
||||||
|
/// or falls back to the first account if none is named "default".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LimilabsEmailService(
|
public class LimilabsEmailService(
|
||||||
IEncryptionService encryptionService,
|
IEncryptionService encryptionService,
|
||||||
IOptions<EmailAccountDto> smtpConfig) : IEmailService
|
IOptions<EmailAccountsOptions> smtpConfig) : IEmailService
|
||||||
{
|
{
|
||||||
private readonly EmailAccountDto _smtpAccount = smtpConfig.Value;
|
|
||||||
|
|
||||||
// Register encoding provider for Limilabs (requires windows-1252 and other code pages)
|
// Register encoding provider for Limilabs (requires windows-1252 and other code pages)
|
||||||
static LimilabsEmailService()
|
static LimilabsEmailService()
|
||||||
{
|
{
|
||||||
@@ -28,14 +29,16 @@ public class LimilabsEmailService(
|
|||||||
|
|
||||||
public async Task SendEmailAsync(string to, string subject, string body, bool isHtml = true, CancellationToken cancellationToken = default)
|
public async Task SendEmailAsync(string to, string subject, string body, bool isHtml = true, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
var smtpAccount = smtpConfig.Value.Accounts.First();
|
||||||
|
|
||||||
using var smtp = new Smtp();
|
using var smtp = new Smtp();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ConnectAndAuthenticateSmtpAsync(smtp);
|
await ConnectAndAuthenticateSmtpAsync(smtp, smtpAccount);
|
||||||
|
|
||||||
var builder = new MailBuilder();
|
var builder = new MailBuilder();
|
||||||
builder.From.Add(new MailBox(_smtpAccount.Username));
|
builder.From.Add(new MailBox(smtpAccount.Username));
|
||||||
builder.To.Add(new MailBox(to));
|
builder.To.Add(new MailBox(to));
|
||||||
builder.Subject = subject;
|
builder.Subject = subject;
|
||||||
|
|
||||||
@@ -74,26 +77,26 @@ public class LimilabsEmailService(
|
|||||||
|
|
||||||
// --- Private Helper Methods ---
|
// --- Private Helper Methods ---
|
||||||
|
|
||||||
private async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp)
|
private async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccountDto smtpAccount)
|
||||||
{
|
{
|
||||||
if (_smtpAccount.SmtpUseSsl)
|
if (smtpAccount.SmtpUseSsl)
|
||||||
{
|
{
|
||||||
smtp.ConnectSSL(_smtpAccount.SmtpServer, _smtpAccount.SmtpPort);
|
smtp.ConnectSSL(smtpAccount.SmtpServer, smtpAccount.SmtpPort);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
smtp.Connect(_smtpAccount.SmtpServer, _smtpAccount.SmtpPort);
|
smtp.Connect(smtpAccount.SmtpServer, smtpAccount.SmtpPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_smtpAccount.UseOAuth2)
|
if (smtpAccount.UseOAuth2)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("OAuth2 is not configured for this SMTP account. UseOAuth2 must be false.");
|
throw new NotSupportedException("OAuth2 is not configured for this SMTP account. UseOAuth2 must be false.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var password = _smtpAccount.PasswordEncrypted ? encryptionService.Decrypt(_smtpAccount.Password) : _smtpAccount.Password;
|
var password = smtpAccount.PasswordEncrypted ? encryptionService.Decrypt(smtpAccount.Password) : smtpAccount.Password;
|
||||||
|
|
||||||
smtp.Login(_smtpAccount.Username, password);
|
smtp.Login(smtpAccount.Username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.CompletedTask; // For async consistency
|
await Task.CompletedTask; // For async consistency
|
||||||
|
|||||||
@@ -67,10 +67,6 @@ try
|
|||||||
// Register Infrastructure layer (RabbitMQ, Repositories, etc.)
|
// Register Infrastructure layer (RabbitMQ, Repositories, etc.)
|
||||||
builder.Services.AddInfrastructure(builder.Configuration);
|
builder.Services.AddInfrastructure(builder.Configuration);
|
||||||
|
|
||||||
// Register EmailAccount configuration (IOptions<EmailAccountDto>)
|
|
||||||
builder.Services.Configure<EmailAccountDto>(
|
|
||||||
builder.Configuration.GetSection("EmailAccount"));
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|||||||
@@ -15,13 +15,18 @@
|
|||||||
"DlqExchangeName": "emailprofiler.emails.dlq",
|
"DlqExchangeName": "emailprofiler.emails.dlq",
|
||||||
"DlqRoutingKey": "email.outbox.dlq"
|
"DlqRoutingKey": "email.outbox.dlq"
|
||||||
},
|
},
|
||||||
"EmailAccount": {
|
"EmailAccounts": {
|
||||||
"Username": "test-flow@digitaldata.works",
|
"Accounts": [
|
||||||
"Password": "ddemail108",
|
{
|
||||||
"PasswordEncrypted": false,
|
"Name": "1",
|
||||||
"SmtpServer": "kundencenter.triplew.de",
|
"Username": "test-flow@digitaldata.works",
|
||||||
"SmtpPort": 465,
|
"Password": "ddemail108",
|
||||||
"SmtpUseSsl": true,
|
"PasswordEncrypted": false,
|
||||||
"UseOAuth2": false
|
"SmtpServer": "kundencenter.triplew.de",
|
||||||
|
"SmtpPort": 465,
|
||||||
|
"SmtpUseSsl": true,
|
||||||
|
"UseOAuth2": false
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user