Refactor: Replace EmailAccountDto with EmailAccount

Replaced the `EmailAccountDto` class with the `EmailAccount` class across the codebase to consolidate the `EmailAccount` entity into the domain layer. Updated namespaces, method signatures, property types, and test cases to reflect this change.

Moved `EmailAccount` from `DigitalData.MessagingService.Application.Common.Dto` to `DigitalData.MessagingService.Domain.Entities`. Updated XML documentation and removed redundant project file entries. Adjusted namespaces for related queries, validators, and commands to align with the new structure.

These changes improve separation of concerns and align with domain-driven design principles.
This commit is contained in:
2026-08-12 15:26:15 +02:00
parent 91581649ba
commit b2857c558f
15 changed files with 41 additions and 37 deletions

View File

@@ -1,11 +1,13 @@
namespace DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Application.Common.Dto;
public record EmailContext
{
#if NETFRAMEWORK
public EmailAccountDto Sender { get; set; } = null!;
public EmailAccount Sender { get; set; } = null!;
#else
public required EmailAccountDto Sender { get; init; }
public required EmailAccount Sender { get; init; }
#endif
/// <summary>

View File

@@ -1,6 +1,7 @@
#if NET
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Application.Common.Dto.MailSearch;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Application.Common.Interfaces;
@@ -19,7 +20,7 @@ public interface IImapEmailService
/// </param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<IEnumerable<ReceivedEmailDto>> FetchEmailsAsync(
EmailAccountDto account,
EmailAccount account,
MailSearchFilter filter,
CancellationToken cancellationToken = default);
@@ -27,7 +28,7 @@ public interface IImapEmailService
/// Marks a message as seen (read) on the server.
/// </summary>
Task MarkAsSeenAsync(
EmailAccountDto account,
EmailAccount account,
long uid,
string folder = "INBOX",
CancellationToken cancellationToken = default);

View File

@@ -1,10 +1,10 @@
#if NET
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Application.Common.Options;
/// <summary>
/// Wrapper options class that holds a list of <see cref="EmailAccountDto"/> entries
/// Wrapper options class that holds a list of <see cref="Dto.EmailAccount"/> entries
/// bound from the <c>EmailAccounts</c> configuration section.
/// </summary>
public class EmailAccountsOptions
@@ -14,7 +14,7 @@ public class EmailAccountsOptions
/// <summary>
/// The list of configured email accounts.
/// </summary>
public required IEnumerable<EmailAccountDto> Accounts { get; init; } = [];
public required IEnumerable<EmailAccount> Accounts { get; init; } = [];
/// <summary>
/// How often the IMAP sync worker polls for new emails, in seconds.

View File

@@ -1,13 +1,13 @@
#if NET
using DigitalData.MessagingService.Application.Common.Options;
using DigitalData.MessagingService.Application.Common.Dto;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Application.EmailAccount.Queries;
namespace DigitalData.MessagingService.Application.EmailAccounts.Queries;
public record GetSenderQuery : IRequest<EmailAccountDto?>
public record GetSenderQuery : IRequest<EmailAccount?>
{
public int? Id { get; init; }
@@ -19,9 +19,9 @@ public record GetSenderQuery : IRequest<EmailAccountDto?>
/// </summary>
/// <param name="Options"></param>
/// <param name="Logger"></param>
public class GetSenderQueryHandler(IOptions<EmailAccountsOptions> Options, ILogger<GetSenderQueryHandler> Logger) : IRequestHandler<GetSenderQuery, EmailAccountDto?>
public class GetSenderQueryHandler(IOptions<EmailAccountsOptions> Options, ILogger<GetSenderQueryHandler> Logger) : IRequestHandler<GetSenderQuery, EmailAccount?>
{
public Task<EmailAccountDto?> Handle(GetSenderQuery request, CancellationToken cancellationToken)
public Task<EmailAccount?> Handle(GetSenderQuery request, CancellationToken cancellationToken)
{
var accounts = request.Id is not null
? Options.Value.Accounts.Where(a => a.Id == request.Id)

View File

@@ -1,8 +1,8 @@
#if NET
using DigitalData.MessagingService.Application.EmailAccount.Queries;
using DigitalData.MessagingService.Application.EmailAccounts.Queries;
using FluentValidation;
namespace DigitalData.MessagingService.Application.EmailAccount.Validators;
namespace DigitalData.MessagingService.Application.EmailAccounts.Validators;
/// <summary>
/// Validator for <see cref="GetSenderQuery"/>.

View File

@@ -1,6 +1,6 @@
#if NET
using DigitalData.MessagingService.Application.Common.Interfaces;
using DigitalData.MessagingService.Application.EmailAccount.Queries;
using DigitalData.MessagingService.Application.EmailAccounts.Queries;
using DigitalData.MessagingService.Domain.Exceptions;
using MediatR;

View File

@@ -2,7 +2,7 @@
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Application.Common.Dto.MailSearch;
using DigitalData.MessagingService.Application.Common.Interfaces;
using DigitalData.MessagingService.Application.EmailAccount.Queries;
using DigitalData.MessagingService.Application.EmailAccounts.Queries;
using DigitalData.MessagingService.Domain.Exceptions;
using MediatR;

View File

@@ -1,11 +1,11 @@
#if NET
using AutoMapper;
using DigitalData.MessagingService.Application.EmailAccount.Queries;
using DigitalData.MessagingService.Domain.Exceptions;
using DigitalData.MessagingService.Application.Common.Dto;
using MediatR;
using System.Text.Json.Serialization;
using DigitalData.MessagingService.Application.Common.Interfaces;
using DigitalData.MessagingService.Application.EmailAccounts.Queries;
namespace DigitalData.MessagingService.Application.EmailSending.Commands;

View File

@@ -11,8 +11,4 @@
<PackageReference Include="MediatR" Version="12.2.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Entities\" />
</ItemGroup>
</Project>

View File

@@ -1,9 +1,9 @@
namespace DigitalData.MessagingService.Application.Common.Dto;
namespace DigitalData.MessagingService.Domain.Entities;
/// <summary>
/// DTO for a single email account configuration.
/// </summary>
public class EmailAccountDto
public class EmailAccount
{
/// <summary>
/// Logical name to identify this account (e.g. "default", "support").

View File

@@ -6,6 +6,7 @@ using Limilabs.Mail;
using Limilabs.Mail.Headers;
using DigitalData.MessagingService.Infrastructure.Services.Extensions;
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Infrastructure.Services;
@@ -13,7 +14,7 @@ namespace DigitalData.MessagingService.Infrastructure.Services;
/// Email service using Limilabs Mail.dll for SMTP operations (send-only).
/// Commercial-grade library with superior Exchange support.
/// SMTP configuration is injected via IOptions&lt;EmailAccountsOptions&gt; from appsettings.json.
/// Uses the first account in the list whose <see cref="EmailAccountDto.Name"/> equals <c>"default"</c>,
/// Uses the first account in the list whose <see cref="EmailAccount.Name"/> equals <c>"default"</c>,
/// or falls back to the first account if none is named "default".
/// </summary>
public class LimilabsEmailService() : IEmailService
@@ -70,7 +71,7 @@ public class LimilabsEmailService() : IEmailService
}
}
private static async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccountDto smtpAccount)
private static async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccount smtpAccount)
{
if (smtpAccount.SmtpUseSsl)
{

View File

@@ -1,6 +1,7 @@
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Application.Common.Dto.MailSearch;
using DigitalData.MessagingService.Application.Common.Interfaces;
using DigitalData.MessagingService.Domain.Entities;
using DigitalData.MessagingService.Domain.Exceptions;
using DigitalData.MessagingService.Infrastructure.Services.Extensions;
using Limilabs.Client.IMAP;
@@ -26,7 +27,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
// Public API
public async Task<IEnumerable<ReceivedEmailDto>> FetchEmailsAsync(
EmailAccountDto account,
EmailAccount account,
MailSearchFilter filter,
CancellationToken cancel = default)
{
@@ -188,7 +189,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
}
public async Task MarkAsSeenAsync(
EmailAccountDto account,
EmailAccount account,
long uid,
string folder = "INBOX",
CancellationToken cancel = default)
@@ -213,7 +214,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
}
}
private static async Task<Imap> OpenAsync(EmailAccountDto account, string folder, CancellationToken cancel)
private static async Task<Imap> OpenAsync(EmailAccount account, string folder, CancellationToken cancel)
{
var imap = new Imap();

View File

@@ -1,5 +1,6 @@
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Client;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Tests.Integration;
@@ -77,7 +78,7 @@ public sealed class EmailSenderTests
{
var email = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = ["hakanttek@gmail.com"],
Subject = "EmailSender.Send Integration Test",
Body = "<p>Sent via EmailSender static client.</p>",
@@ -94,7 +95,7 @@ public sealed class EmailSenderTests
{
var email = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = ["hakanttek@gmail.com"],
Subject = "Plain Text Test",
Body = "This is a plain text email.",

View File

@@ -1,5 +1,6 @@
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Client;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Tests.Integration;
@@ -57,7 +58,7 @@ public sealed class EmailSenderUrlOverloadTests
{
var email = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = ["url-overload-test@example.com"],
Subject = "URL Overload Integration Test",
Body = "<p>Sent after URL-based connection.</p>",

View File

@@ -5,6 +5,7 @@ using DigitalData.MessagingService.RabbitMQ;
using Microsoft.Extensions.DependencyInjection;
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Application.Common.Interfaces;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Tests.Integration;
@@ -38,7 +39,7 @@ public sealed class SendingEmailPublisherTests : IAsyncDisposable
Id = Guid.NewGuid(),
Mail = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = ["test@example.com"],
Subject = "Integration Test - EnqueueAsync",
Body = "<p>Hello from integration test.</p>",
@@ -67,8 +68,8 @@ public sealed class SendingEmailPublisherTests : IAsyncDisposable
Id = Guid.NewGuid(),
Mail = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = new List<string> { $"recipient{i}@example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = [$"recipient{i}@example.com"],
Subject = $"Integration Test - Batch #{i}",
Body = $"Batch message {i}",
IsHtml = false,
@@ -94,7 +95,7 @@ public sealed class SendingEmailPublisherTests : IAsyncDisposable
Id = Guid.NewGuid(),
Mail = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = ["depth-test@example.com"],
Subject = "Integration Test - GetQueueDepth",
Body = "Queue depth test",
@@ -121,7 +122,7 @@ public sealed class SendingEmailPublisherTests : IAsyncDisposable
Id = id,
Mail = new EmailContext
{
Sender = new EmailAccountDto { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Sender = new EmailAccount { Username = "test@example.com", Password = "password", SmtpServer = "smtp.example.com" },
Recipients = new List<string> { "serialize@example.com" },
Subject = "Serialization Test",
Body = "<strong>Bold</strong>",