using System.Net; using System.Net.Mail; namespace JobTrackerApi.Services; public interface IAppEmailSender { Task SendAsync(string toEmail, string subject, string bodyText, CancellationToken cancellationToken = default); } public sealed class SmtpEmailSender : IAppEmailSender { private readonly IEmailSettingsResolver _settings; private readonly ILogger _logger; public SmtpEmailSender(IEmailSettingsResolver settings, ILogger logger) { _settings = settings; _logger = logger; } public async Task SendAsync(string toEmail, string subject, string bodyText, CancellationToken cancellationToken = default) { var snapshot = await _settings.GetSnapshotAsync(cancellationToken); var host = snapshot.Host; var user = snapshot.User; var pass = snapshot.Password; var from = snapshot.From; var fromName = snapshot.FromName; var port = snapshot.Port; var enableSsl = snapshot.EnableSsl; var timeoutMs = snapshot.TimeoutMs; var enabled = snapshot.Enabled; if (!enabled) { _logger.LogWarning("Email sending is disabled. Suppressed email to {To} subject={Subject}", toEmail, subject); return; } if (string.IsNullOrWhiteSpace(host)) throw new InvalidOperationException("Email:SmtpHost is not configured."); if (string.IsNullOrWhiteSpace(from)) throw new InvalidOperationException("Email:From is not configured."); using var msg = new MailMessage(); msg.From = new MailAddress(from, string.IsNullOrWhiteSpace(fromName) ? null : fromName); msg.To.Add(new MailAddress(toEmail)); msg.Subject = subject; msg.Body = bodyText; msg.IsBodyHtml = false; using var smtp = new SmtpClient(host, port) { EnableSsl = enableSsl, DeliveryMethod = SmtpDeliveryMethod.Network, Timeout = timeoutMs, }; if (!string.IsNullOrWhiteSpace(user)) { smtp.Credentials = new NetworkCredential(user, pass); } await Task.Run(() => smtp.Send(msg), cancellationToken); } }