using System.Net; using System.Net.Mail; using HrynCo.DAL.Abstract; using HrynCo.NotificationService.DAL.Abstract.Providers; using HrynCo.NotificationService.DAL.Abstract.Repositories; using HrynCo.NotificationService.Services.Core; using HrynCo.NotificationService.Services.Logging; using static HrynCo.NotificationService.Services.Core.ServiceResultHelper; namespace HrynCo.NotificationService.Services.EmailChannels.Send; internal sealed class SendEmailHandler : RequestHandler> { private readonly IEmailChannelRepository _channels; private readonly IEmailChannelUsageRepository _usage; public SendEmailHandler( IContextualSerilogLogger logger, IUnitOfWork unitOfWork, IEmailChannelRepository channels, IEmailChannelUsageRepository usage) : base(logger, unitOfWork) { _channels = channels; _usage = usage; } protected override async Task> DoOnHandle( SendEmailCommand request, CancellationToken cancellationToken) { var channel = await _channels.GetByIdAsync(request.ChannelId, cancellationToken); if (channel is null) return Failure($"Channel '{request.ChannelId}' not found."); if (channel.Settings is not SmtpChannelSettings smtp) return Failure($"Channel type '{channel.EmailChannelType}' is not supported for sending."); try { using var client = new SmtpClient(smtp.Host, smtp.Port) { EnableSsl = smtp.UseSsl, Credentials = string.IsNullOrWhiteSpace(smtp.Username) ? null : new NetworkCredential(smtp.Username, smtp.Password) }; using var mail = new MailMessage { From = new MailAddress(smtp.FromEmail, smtp.FromName), Subject = request.Subject, Body = request.HtmlBody, IsBodyHtml = true }; if (!string.IsNullOrWhiteSpace(request.TextBody)) { var plain = AlternateView.CreateAlternateViewFromString(request.TextBody, null, "text/plain"); mail.AlternateViews.Add(plain); } mail.To.Add(new MailAddress(request.RecipientEmail, request.RecipientName)); await client.SendMailAsync(mail, cancellationToken); } catch (Exception ex) { Logger.Error(ex, "SMTP send failed for channel {ChannelId}", request.ChannelId); return Failure(ex.Message); } await _usage.IncrementUsageAsync( request.ChannelId, DateOnly.FromDateTime(DateTime.UtcNow), cancellationToken); return Success(Unit.Value); } }