using CarCareTracker.Models; using MimeKit; using MailKit.Net.Smtp; using MailKit.Security; namespace CarCareTracker.Helper { public interface IMailHelper { OperationResponse NotifyUserForRegistration(string emailAddress, string token); OperationResponse NotifyUserForPasswordReset(string emailAddress, string token); OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token); OperationResponse NotifyUserForReminders(Vehicle vehicle, List emailAddresses, List reminders); OperationResponse SendTestEmail(string emailAddress); } public class MailHelper : IMailHelper { private readonly MailConfig mailConfig; private readonly string serverLanguage; private readonly IFileHelper _fileHelper; private readonly ITranslationHelper _translator; private readonly ILogger _logger; public MailHelper( IConfigHelper config, IFileHelper fileHelper, ITranslationHelper translationHelper, ILogger logger ) { //load mailConfig from Configuration mailConfig = config.GetMailConfig(); serverLanguage = config.GetServerLanguage(); _fileHelper = fileHelper; _translator = translationHelper; _logger = logger; } public OperationResponse NotifyUserForRegistration(string emailAddress, string token) { if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { return OperationResponse.Failed("SMTP Server Not Setup"); } if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token)) { return OperationResponse.Failed("Email Address or Token is invalid"); } string emailSubject = _translator.Translate(serverLanguage, "Your Registration Token for LubeLogger"); string emailBody = $"{_translator.Translate(serverLanguage, "A token has been generated on your behalf, please complete your registration for LubeLogger using the token")}: {token}"; var result = SendEmail(new List { emailAddress }, emailSubject, emailBody); if (result) { return OperationResponse.Succeed("Email Sent!"); } else { return OperationResponse.Failed(); } } public OperationResponse NotifyUserForPasswordReset(string emailAddress, string token) { if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { return OperationResponse.Failed("SMTP Server Not Setup"); } if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token)) { return OperationResponse.Failed("Email Address or Token is invalid"); } string emailSubject = _translator.Translate(serverLanguage, "Your Password Reset Token for LubeLogger"); string emailBody = $"{_translator.Translate(serverLanguage, "A token has been generated on your behalf, please reset your password for LubeLogger using the token")}: {token}"; var result = SendEmail(new List { emailAddress }, emailSubject, emailBody); if (result) { return OperationResponse.Succeed("Email Sent!"); } else { return OperationResponse.Failed(); } } public OperationResponse SendTestEmail(string emailAddress) { if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { return OperationResponse.Failed("SMTP Server Not Setup"); } if (string.IsNullOrWhiteSpace(emailAddress)) { return OperationResponse.Failed("Email Address or Token is invalid"); } string emailSubject = _translator.Translate(serverLanguage, "Test Email from LubeLogger"); string emailBody = _translator.Translate(serverLanguage, "If you are seeing this email it means your SMTP configuration is functioning correctly"); var result = SendEmail(new List { emailAddress }, emailSubject, emailBody); if (result) { return OperationResponse.Succeed("Email Sent!"); } else { return OperationResponse.Failed(); } } public OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token) { if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { return OperationResponse.Failed("SMTP Server Not Setup"); } if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token)) { return OperationResponse.Failed("Email Address or Token is invalid"); } string emailSubject = _translator.Translate(serverLanguage, "Your User Account Update Token for LubeLogger"); string emailBody = $"{_translator.Translate(serverLanguage, "A token has been generated on your behalf, please update your account for LubeLogger using the token")}: {token}"; var result = SendEmail(new List { emailAddress}, emailSubject, emailBody); if (result) { return OperationResponse.Succeed("Email Sent!"); } else { return OperationResponse.Failed(); } } public OperationResponse NotifyUserForReminders(Vehicle vehicle, List emailAddresses, List reminders) { if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { return OperationResponse.Failed("SMTP Server Not Setup"); } if (!emailAddresses.Any()) { return OperationResponse.Failed("No recipients could be found"); } if (!reminders.Any()) { return OperationResponse.Failed("No reminders could be found"); } //get email template, this file has to exist since it's a static file. var emailTemplatePath = _fileHelper.GetFullFilePath(StaticHelper.ReminderEmailTemplate); string emailSubject = $"{_translator.Translate(serverLanguage, "Vehicle Reminders From LubeLogger")} - {DateTime.Now.ToShortDateString()}"; //construct html table. string emailBody = File.ReadAllText(emailTemplatePath); emailBody = emailBody.Replace("{VehicleInformation}", $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{StaticHelper.GetVehicleIdentifier(vehicle)}"); string tableHeader = $"{_translator.Translate(serverLanguage, "Urgency")}{_translator.Translate(serverLanguage, "Description")}{_translator.Translate(serverLanguage, "Due")}"; string tableBody = ""; foreach(ReminderRecordViewModel reminder in reminders) { var dueOn = reminder.Metric == ReminderMetric.Both ? $"{reminder.Date.ToShortDateString()} or {reminder.Mileage}" : reminder.Metric == ReminderMetric.Date ? $"{reminder.Date.ToShortDateString()}" : $"{reminder.Mileage}"; tableBody += $"{_translator.Translate(serverLanguage, StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency))}{reminder.Description}{dueOn}"; } emailBody = emailBody.Replace("{TableHeader}", tableHeader).Replace("{TableBody}", tableBody); try { var result = SendEmail(emailAddresses, emailSubject, emailBody); if (result) { return OperationResponse.Succeed("Email Sent!"); } else { return OperationResponse.Failed(); } } catch (Exception ex) { return OperationResponse.Failed(ex.Message); } } private bool SendEmail(List emailTo, string emailSubject, string emailBody) { string from = mailConfig.EmailFrom; var server = mailConfig.EmailServer; var message = new MimeMessage(); message.From.Add(new MailboxAddress(from, from)); foreach(string emailRecipient in emailTo) { message.To.Add(new MailboxAddress(emailRecipient, emailRecipient)); } message.Subject = emailSubject; var builder = new BodyBuilder(); builder.HtmlBody = emailBody; message.Body = builder.ToMessageBody(); using (var client = new SmtpClient()) { client.Connect(server, mailConfig.Port, SecureSocketOptions.Auto); //perform authentication if either username or password is provided. //do not perform authentication if neither are provided. if (!string.IsNullOrWhiteSpace(mailConfig.Username) || !string.IsNullOrWhiteSpace(mailConfig.Password)) { client.Authenticate(mailConfig.Username, mailConfig.Password); } try { client.Send(message); client.Disconnect(true); return true; } catch (Exception ex) { _logger.LogError(ex.Message); return false; } } } } }