using Application.Abstractions.Cache; using Application.Abstractions.Messaging.Email; using Application.Features.Config.Get; using Infrastructure.Persistence; using SharedKernel; using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Infrastructure.Messaging.Email { public class MailService : IMailService { private readonly ILogger _logger; private readonly ICacheService _cache; private readonly AppSettings.SmtpSection _smtp; private readonly AppDbContext _db; // SMTP 정보 public string Host { get; set; } = default!; public int Port { get; set; } = 587; public string? User { get; set; } public string? Password { get; set; } public bool UseStartTls { get; set; } = true; public string FromEmail { get; set; } = default!; public string FromName { get; set; } = "no-reply"; public MailService(ILogger logger, ICacheService cache, IOptions options, AppDbContext db) { _logger = logger; _cache = cache; _smtp = options.Value.SMTP; _db = db; } public async Task SendAsync(SendData data, CancellationToken ct = default) { _logger.LogInformation("Sending email to {ToAddress} with subject {Subject}", data.ToAddress, data.Subject); // 1. Redis 캐시에서 Config 조회 var config = await _cache.GetAsync(CacheKeys.Config, ct); if (config is null) { var entity = await _db.Config.AsNoTracking().OrderByDescending(x => x.ID).FirstOrDefaultAsync(); if (entity is null) { Host = _smtp.Host; Port = _smtp.Port; User = _smtp.User; Password = _smtp.Password; UseStartTls = _smtp.UseStartTls; FromEmail = _smtp.FromEmail; FromName = _smtp.FromName; } else { Host = entity.Basic.SmtpServer ?? ""; Port = entity.Basic.SmtpPort ?? 587; UseStartTls = entity.Basic.SmtpEnableSSL; User = entity.Basic.SmtpUsername; Password = entity.Basic.SmtpPassword; FromEmail = entity.Basic.FromEmail ?? ""; FromName = entity.Basic.FromName ?? ""; } } else { Host = config.Basic.SmtpServer!; Port = config.Basic.SmtpPort! ?? 587; UseStartTls = config.Basic.SmtpEnableSSL; User = config.Basic.SmtpUsername; Password = config.Basic.SmtpPassword; FromEmail = config.Basic.FromEmail!; FromName = config.Basic.FromName!; } var message = new MimeMessage(); message.From.Add(new MailboxAddress(FromName, FromEmail)); message.To.Add(MailboxAddress.Parse(data.ToAddress)); message.Subject = data.Subject; var body = new BodyBuilder { HtmlBody = data.MessageHtml, TextBody = data.MessageText }; message.Body = body.ToMessageBody(); using var client = new SmtpClient(); var secure = Port == 465 ? SecureSocketOptions.SslOnConnect : UseStartTls ? SecureSocketOptions.StartTls : SecureSocketOptions.Auto; await client.ConnectAsync(Host, Port, secure, ct); if (!string.IsNullOrWhiteSpace(User)) { await client.AuthenticateAsync(User, Password, ct); } await client.SendAsync(message, ct); await client.DisconnectAsync(true, ct); _logger.LogInformation("Email sent to {ToAddress} with subject {Subject}", data.ToAddress, data.Subject); } } }