Refactor email services and update password handling

Updated `EmailAccountDto` to use `required` properties for .NET 7+ compatibility, removing the `PasswordEncrypted` property and simplifying password handling.

Removed `IEncryptionService` dependency from `LimilabsEmailService` and `LimilabsImapEmailService`. Updated `ConnectAndAuthenticateSmtpAsync` and `OpenAsync` methods to remove password decryption logic.

Introduced `CancellationToken` support in `LimilabsImapEmailService` methods to improve cancellation handling for IMAP operations.

Added `Entities\` folder reference in `DigitalData.MessagingService.Domain.csproj`.
This commit is contained in:
2026-08-12 14:24:17 +02:00
parent 176e6dd6c5
commit 5e0de6d52a
4 changed files with 24 additions and 29 deletions

View File

@@ -22,8 +22,6 @@ public class EmailAccountDto
public string Password { get; set; } = null!; public string Password { get; set; } = null!;
#endif #endif
public bool PasswordEncrypted { get; set; } = false;
#if NET #if NET
public required string SmtpServer { get; set; } public required string SmtpServer { get; set; }
#else #else

View File

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

View File

@@ -16,8 +16,7 @@ namespace DigitalData.MessagingService.Infrastructure.Services;
/// 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="EmailAccountDto.Name"/> equals <c>"default"</c>,
/// or falls back to the first account if none is named "default". /// or falls back to the first account if none is named "default".
/// </summary> /// </summary>
public class LimilabsEmailService( public class LimilabsEmailService() : IEmailService
IEncryptionService encryptionService) : IEmailService
{ {
// 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()
@@ -71,7 +70,7 @@ public class LimilabsEmailService(
} }
} }
private async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccountDto smtpAccount) private static async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccountDto smtpAccount)
{ {
if (smtpAccount.SmtpUseSsl) if (smtpAccount.SmtpUseSsl)
{ {
@@ -88,9 +87,7 @@ public class LimilabsEmailService(
} }
else else
{ {
var password = smtpAccount.PasswordEncrypted ? encryptionService.Decrypt(smtpAccount.Password) : smtpAccount.Password; await smtp.LoginAsync(smtpAccount.Username, smtpAccount.Password);
await smtp.LoginAsync(smtpAccount.Username, password);
} }
} }

View File

@@ -31,9 +31,9 @@ public class LimilabsImapEmailService(
public async Task<IEnumerable<ReceivedEmailDto>> FetchEmailsAsync( public async Task<IEnumerable<ReceivedEmailDto>> FetchEmailsAsync(
EmailAccountDto account, EmailAccountDto account,
MailSearchFilter filter, MailSearchFilter filter,
CancellationToken cancellationToken = default) CancellationToken cancel = default)
{ {
using var imap = await OpenAsync(account, filter.Folder); using var imap = await OpenAsync(account, filter.Folder, cancel);
try try
{ {
#region Find UIDs #region Find UIDs
@@ -51,7 +51,7 @@ public class LimilabsImapEmailService(
} }
var searchExpression = criterions.Count > 0 ? Expression.And([.. criterions]) : Expression.All(); var searchExpression = criterions.Count > 0 ? Expression.And([.. criterions]) : Expression.All();
List<long> uids = [.. await imap.SearchAsync(searchExpression, cancellationToken)]; List<long> uids = [.. await imap.SearchAsync(searchExpression, cancel)];
if (filter.SortOrder == MailSortOrder.NewestFirst) if (filter.SortOrder == MailSortOrder.NewestFirst)
uids.Reverse(); uids.Reverse();
@@ -64,7 +64,7 @@ public class LimilabsImapEmailService(
foreach (var uid in uids) foreach (var uid in uids)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancel.ThrowIfCancellationRequested();
try try
{ {
@@ -73,9 +73,9 @@ public class LimilabsImapEmailService(
CacheKeyPrefix + uid, CacheKeyPrefix + uid,
async entry => async entry =>
{ {
var eml = await imap.GetMessageByUIDAsync(uid, cancellationToken); var eml = await imap.GetMessageByUIDAsync(uid, cancel);
var mail = new MailBuilder().CreateFromEml(eml); var mail = new MailBuilder().CreateFromEml(eml);
var flags = await imap.GetFlagsByUIDAsync(uid, cancellationToken); var flags = await imap.GetFlagsByUIDAsync(uid, cancel);
var attachments = new List<EmailAttachmentDto>(); var attachments = new List<EmailAttachmentDto>();
@@ -169,7 +169,7 @@ public class LimilabsImapEmailService(
} }
} }
await imap.CloseAsync(cancellationToken); await imap.CloseAsync(cancel);
if (filter.MaxCount is int maxCount && maxCount > 0 && results.Count > maxCount) if (filter.MaxCount is int maxCount && maxCount > 0 && results.Count > maxCount)
return results.Take(maxCount); return results.Take(maxCount);
@@ -194,13 +194,13 @@ public class LimilabsImapEmailService(
EmailAccountDto account, EmailAccountDto account,
long uid, long uid,
string folder = "INBOX", string folder = "INBOX",
CancellationToken cancellationToken = default) CancellationToken cancel = default)
{ {
using var imap = await OpenAsync(account, folder); using var imap = await OpenAsync(account, folder, cancel);
try try
{ {
await imap.MarkMessageSeenByUIDAsync(uid, cancellationToken); await imap.MarkMessageSeenByUIDAsync(uid, cancel);
await imap.CloseAsync(cancellationToken); await imap.CloseAsync(cancel);
} }
catch (Limilabs.Client.ServerException ex) catch (Limilabs.Client.ServerException ex)
{ {
@@ -216,25 +216,21 @@ public class LimilabsImapEmailService(
} }
} }
private async Task<Imap> OpenAsync(EmailAccountDto account, string folder) private static async Task<Imap> OpenAsync(EmailAccountDto account, string folder, CancellationToken cancel)
{ {
var imap = new Imap(); var imap = new Imap();
if (account.ImapUseSsl) if (account.ImapUseSsl)
await imap.ConnectSSLAsync(account.ImapServer!, account.ImapPort); await imap.ConnectSSLAsync(account.ImapServer!, account.ImapPort, cancel: cancel);
else else
await imap.ConnectAsync(account.ImapServer!, account.ImapPort); await imap.ConnectAsync(account.ImapServer!, account.ImapPort, cancel: cancel);
var password = account.PasswordEncrypted await imap.LoginAsync(account.Username, account.Password, cancel);
? EncryptionService.Decrypt(account.Password)
: account.Password;
await imap.LoginAsync(account.Username, password);
if (string.Equals(folder, "INBOX", StringComparison.OrdinalIgnoreCase)) if (string.Equals(folder, "INBOX", StringComparison.OrdinalIgnoreCase))
await imap.SelectInboxAsync(); await imap.SelectInboxAsync(cancel);
else else
await imap.SelectAsync(folder); await imap.SelectAsync(folder, cancel);
return imap; return imap;
} }