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;
///
/// 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 equals "default",
/// or falls back to the first account if none is named "default".
///
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 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);
}
}
}