using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Mail; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services { public class EmailService : IEmailService { private readonly IBackgroundWorkerService backgroundWorker; private readonly bool IsConfigured; private readonly string sender; private readonly string smtpServer; private readonly string smtpPassword; public EmailService(IBackgroundWorkerService backgroundWorker, IConfiguration configuration) { sender = configuration.GetValue("email:sender", null); smtpPassword = configuration.GetValue("email:password", null); smtpServer = configuration.GetValue("email:smtpServer", null); var configError = (string.IsNullOrEmpty(sender) || string.IsNullOrEmpty(smtpPassword) || string.IsNullOrEmpty(smtpServer)); IsConfigured = !configError; this.backgroundWorker = backgroundWorker; } public void EnqueueSend(IEnumerable addresses, string subject, string htmlBody) { if(!IsConfigured) { Trace.TraceWarning("smtp is not configured"); return; } var jobId = CalcJobId(addresses, subject, htmlBody); if (!backgroundWorker.Contains(jobId)) { var action = MakeEmailSendJobAsync(addresses, subject, htmlBody); backgroundWorker.Enqueue(jobId, action); } } private Func MakeEmailSendJobAsync(IEnumerable addresses, string subject, string htmlBody) { var mailAddresses = new List(); foreach (var address in addresses) { if (MailAddress.TryCreate(address, out MailAddress mailAddress)) mailAddresses.Add(mailAddress); else Trace.TraceWarning($"Mail {address} is not correct."); } if (!mailAddresses.Any()) throw new ArgumentException($"No valid email found. List:[{string.Join(',', addresses)}]", nameof(addresses)); if (string.IsNullOrEmpty(subject)) throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(subject)); var func = async (string id, CancellationToken token) => { var from = new MailAddress(sender); var message = new MailMessage(); message.From = from; foreach (var mailAddress in mailAddresses) message.To.Add(mailAddress); message.Subject = subject; message.Body = htmlBody; message.IsBodyHtml = true; var client = new SmtpClient(smtpServer); client.EnableSsl = true; client.UseDefaultCredentials = false; client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); // TODO: uncomment next when tested //await client.SendMailAsync(message, token); await Task.Delay(0); Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject}"); }; return func; } private string CalcJobId(IEnumerable addresses, string subject, string content) { var hash = GetHashCode(addresses); hash ^= subject.GetHashCode(); hash ^= content.GetHashCode(); return hash.ToString("x"); } private static int GetHashCode(IEnumerable strings) { int hash = -1397075115; var enumerator = strings.GetEnumerator(); while(enumerator.MoveNext()) hash ^= enumerator.Current.GetHashCode(); return hash; } } }