using MailKit; using MailKit.Net.Smtp; using MailKit.Security; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MimeKit; using MTWorkHR.Core.Email; using MTWorkHR.Core.Entities; using MTWorkHR.Core.Global; //using SendGrid; //using SendGrid.Helpers.Mail; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace MTWorkHR.Infrastructure.EmailService { public class MailSender : IMailSender { public AppSettingsConfiguration _configuration { get; } private readonly ILogger _logger; public MailSender(AppSettingsConfiguration configuration,ILogger logger) { _configuration = configuration; _logger = logger; } //public async Task SendEmailGrid(EmailMessage email) //{ // var client = new SendGridClient(_configuration.MailSettings.ApiKey); // var to = new EmailAddress(email.To); // var from = new EmailAddress // { // Email = _configuration.MailSettings.FromAddress, // Name = _configuration.MailSettings.FromName // }; // email.Body = email.Body + " /n" + email.url; // var message = MailHelper.CreateSingleEmail(from, to, email.Subject, email.Body, email.Body); // var response = await client.SendEmailAsync(message); // return response.IsSuccessStatusCode; //} /// /// Send Email using an azure email address, smtpUserName and password /// /// /// public async Task SendEmailAzure(EmailMessage email) { var mailTo = email.To; var settings = _configuration.MailSettings; // Validate configuration settings if (string.IsNullOrEmpty(settings.SmtpUsername) || string.IsNullOrEmpty(settings.Password) || string.IsNullOrEmpty(settings.FromAddress) || string.IsNullOrEmpty(settings.Host) || settings.Port == 0 || string.IsNullOrEmpty(mailTo)) { Console.WriteLine("Invalid mail settings or recipient address."); return false; } // Create the email message var emailObj = new MimeMessage(); emailObj.From.Add(new MailboxAddress("MTWork", settings.FromAddress)); // Display name + verified sender address emailObj.Sender = MailboxAddress.Parse(settings.FromAddress); emailObj.To.Add(MailboxAddress.Parse(mailTo)); emailObj.Subject = email.Subject; // Build the email body with HTML content var builder = new BodyBuilder(); var emailBody = email.Body; if (!string.IsNullOrEmpty(email.url)) { // Use string interpolation with proper HTML escaping emailBody += $"Please click on this link or copy the following URL and open it: '{WebUtility.HtmlEncode(email.url)}'"; } builder.HtmlBody = emailBody; emailObj.Body = builder.ToMessageBody(); // Initialize SMTP client with logging //using var logger = new ProtocolLogger("smtp.log", append: false); using var smtp = new SmtpClient(); try { _logger.LogInformation("Connecting to SMTP server {Host}:{Port} with username :[{SmtpUsername}]", settings.Host, settings.Port, settings.SmtpUsername); // Connect to Azure Communication Services SMTP server await smtp.ConnectAsync(settings.Host, settings.Port, SecureSocketOptions.StartTls); _logger.LogInformation("Authenticating with username {SmtpUsername}:[{pass}]", settings.SmtpUsername, settings.Password); // Authenticate using SMTP Username and Entra app client secret await smtp.AuthenticateAsync(settings.SmtpUsername, settings.Password); _logger.LogInformation("Sending email to {To} with subject {Subject}", mailTo, email.Subject); // Send the email await smtp.SendAsync(emailObj); _logger.LogInformation("Email sent successfully to {To}", mailTo); } catch (AuthenticationException ex) { _logger.LogError(ex, "Authentication failed for username {SmtpUsername}: {Message}", settings.SmtpUsername, ex.Message); throw ex; } catch (SmtpCommandException ex) { _logger.LogError(ex, "SMTP error: {Message}, Status: {StatusCode}", ex.Message, ex.StatusCode); throw ex; } catch (Exception ex) { _logger.LogError(ex, "Error sending email to {To}: {Message}", mailTo, ex.Message); throw ex; } finally { // Ensure disconnection if (smtp.IsConnected) { await smtp.DisconnectAsync(true); _logger.LogInformation("Disconnected from SMTP server"); } } return true; } //Send Email using an email address and password public async Task SendEmail(EmailMessage email) { var mailTo = email.To; var settings = _configuration.MailSettings; if (settings.FromAddress == null || settings.FromAddress== "" || settings.Password == null || settings.TemplatePath == null || settings.Host == null || settings.Port == 0 || mailTo == null) return false; //string FilePath = _configuration.MailSettings.TemplatePath; //StreamReader str = new StreamReader(FilePath); //string MailText = str.ReadToEnd(); //str.Close(); //MailText = MailText.Replace("[NotificationType]", email.Subject).Replace("[Info]", email.Body).Replace("[Link]", email.url ); var emailObj = new MimeMessage(); emailObj.From.Add(new MailboxAddress("MTWork", _configuration.MailSettings.FromAddress)); // Ensure From matches authenticated email emailObj.Sender = MailboxAddress.Parse(_configuration.MailSettings.FromAddress); emailObj.To.Add(MailboxAddress.Parse(mailTo)); emailObj.Subject = email.Subject; var builder = new BodyBuilder(); email.Body = email.Body + ( string.IsNullOrEmpty( email.url ) ?"": "Please click on this link or copy the following url and open it : \' " + email.url+"\'"); builder.HtmlBody = email.Body; emailObj.Body = builder.ToMessageBody(); using var logger = new ProtocolLogger("smtp.log", append: false); using var smtp = new SmtpClient(logger); try { await smtp.ConnectAsync(_configuration.MailSettings.Host, _configuration.MailSettings.Port, MailKit.Security.SecureSocketOptions.StartTls); await smtp.AuthenticateAsync(_configuration.MailSettings.FromAddress, _configuration.MailSettings.Password); _logger.LogInformation("Sending email to {To} with subject {Subject}", mailTo, email.Subject); await smtp.SendAsync(emailObj); _logger.LogInformation("Email sent successfully to {To}", mailTo); } catch (AuthenticationException ex) { _logger.LogError(ex, "Authentication failed for username {SmtpUsername}: {Message}", settings.SmtpUsername, ex.Message); throw ex; } catch (SmtpCommandException ex) { _logger.LogError(ex, "SMTP error: {Message}, Status: {StatusCode}", ex.Message, ex.StatusCode); throw ex; } catch (Exception ex) { _logger.LogError(ex, "Error sending email to {To}: {Message}", mailTo, ex.Message); throw ex; } finally { _logger.LogInformation("Disconnected from SMTP server"); await smtp.DisconnectAsync(true); } return true; } } }