The `DigitalData.MessagingService.Publisher.Abstraction` project has been removed, and its functionality has been merged into a new project named `DigitalData.MessagingService.Abstraction`. - Updated namespaces from `Publisher.Abstraction` to `Abstraction` across all relevant files, including DTOs, interfaces, and classes. - Modified the solution file to remove `Publisher.Abstraction` and add `Abstraction`, updating solution configurations and nested project mappings. - Replaced project references to `Publisher.Abstraction` with `Abstraction` in all affected project files. - Updated tests and integration tests to reflect the namespace and project changes. - Refactored application-level files such as `EmailMappingProfile` and `DependencyInjection.cs` to use the new namespace. This refactor simplifies the project structure and ensures consistency across the solution.
100 lines
3.5 KiB
C#
100 lines
3.5 KiB
C#
using System.Text;
|
|
using DigitalData.MessagingService.Application.Common.Interfaces;
|
|
using DigitalData.MessagingService.Domain.Exceptions;
|
|
using Limilabs.Client.SMTP;
|
|
using Limilabs.Mail;
|
|
using Limilabs.Mail.Headers;
|
|
using DigitalData.MessagingService.Infrastructure.Services.Extensions;
|
|
using DigitalData.MessagingService.Abstraction;
|
|
|
|
namespace DigitalData.MessagingService.Infrastructure.Services;
|
|
|
|
/// <summary>
|
|
/// Email service using Limilabs Mail.dll for SMTP operations (send-only).
|
|
/// Commercial-grade library with superior Exchange support.
|
|
/// 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>
|
|
public class LimilabsEmailService(
|
|
IEncryptionService encryptionService) : IEmailService
|
|
{
|
|
// Register encoding provider for Limilabs (requires windows-1252 and other code pages)
|
|
static LimilabsEmailService()
|
|
{
|
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
}
|
|
|
|
public async Task SendEmailAsync(EmailAccountDto from, IEnumerable<string> recipients, string subject, string body, bool isHtml = true, CancellationToken cancellationToken = default)
|
|
{
|
|
using var smtp = new Smtp();
|
|
|
|
try
|
|
{
|
|
await ConnectAndAuthenticateSmtpAsync(smtp, from);
|
|
|
|
var builder = new MailBuilder();
|
|
builder.From.Add(new MailBox(from.Username));
|
|
|
|
foreach (var recipient in recipients)
|
|
builder.To.Add(new MailBox(recipient));
|
|
|
|
builder.Subject = subject;
|
|
|
|
if (isHtml)
|
|
{
|
|
builder.Html = body;
|
|
}
|
|
else
|
|
{
|
|
builder.Text = body;
|
|
}
|
|
|
|
var mail = builder.Create();
|
|
|
|
var result = await smtp.SendMessageAsync(mail, cancellationToken);
|
|
|
|
if (result.Status != SendMessageStatus.Success)
|
|
{
|
|
throw new InvalidOperationException($"Failed to send email. Status: {result.Status}");
|
|
}
|
|
|
|
await smtp.CloseAsync(cancellationToken);
|
|
await Task.CompletedTask; // For async consistency
|
|
}
|
|
catch (Limilabs.Client.ServerException ex)
|
|
{
|
|
await smtp.CloseSafelyAsync();
|
|
throw new AuthenticationFailedException("SMTP authentication failed. Check credentials or OAuth2 configuration.", ex);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await smtp.CloseSafelyAsync();
|
|
throw new InvalidOperationException("Failed to send email via SMTP server.", ex);
|
|
}
|
|
}
|
|
|
|
private async Task ConnectAndAuthenticateSmtpAsync(Smtp smtp, EmailAccountDto smtpAccount)
|
|
{
|
|
if (smtpAccount.SmtpUseSsl)
|
|
{
|
|
await smtp.ConnectSSLAsync(smtpAccount.SmtpServer, smtpAccount.SmtpPort);
|
|
}
|
|
else
|
|
{
|
|
await smtp.ConnectAsync(smtpAccount.SmtpServer, smtpAccount.SmtpPort);
|
|
}
|
|
|
|
if (smtpAccount.UseOAuth2)
|
|
{
|
|
throw new NotSupportedException("OAuth2 is not configured for this SMTP account. UseOAuth2 must be false.");
|
|
}
|
|
else
|
|
{
|
|
var password = smtpAccount.PasswordEncrypted ? encryptionService.Decrypt(smtpAccount.Password) : smtpAccount.Password;
|
|
|
|
await smtp.LoginAsync(smtpAccount.Username, password);
|
|
}
|
|
}
|
|
}
|