using System; using System.Configuration; using System.IO; using System.Linq; using System.Net; using System.Net.Mail; using log4net; using LeafWeb.Core.DAL; using LeafWeb.Core.Entities; using LeafWeb.Core.Utility; namespace LeafWeb.WebCms.Services { public class EmailNotificationService : IDisposable { private static readonly ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly string _emailFromAddress; private const string EmailSuccessSubject = "LeafWeb results"; private const string EmailErrorSubject = "LeafWeb processing error"; private const string EmailSystemErrorSubject = "LeafWeb system error"; private const string EmailCancelledSubject = "LeafWeb cancelled"; /// /// Comma separated values /// private readonly string _adminEmailAddresses; private readonly SmtpClient _smtpClient; private readonly DataService _dataService; private readonly DownloadUrlService _downloadUrlService; private string FormatSubject(string subject, LeafInput leafInput) { return subject + $" - '{leafInput.Identifier}'"; } public EmailNotificationService(DataService dataService) { _dataService = dataService; _downloadUrlService = new DownloadUrlService(); _smtpClient = new SmtpClient( ConfigurationManager.AppSettings["SmtpHost"], Convert.ToInt32(ConfigurationManager.AppSettings["SmtpPort"])); if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["SmtpUserName"])) _smtpClient.Credentials = new NetworkCredential( ConfigurationManager.AppSettings["SmtpUserName"], ConfigurationManager.AppSettings["SmtpPassword"] ); _emailFromAddress = ConfigurationManager.AppSettings["EmailFromAddress"]; _adminEmailAddresses = ConfigurationManager.AppSettings["AdminEmailAddresses"]; } public EmailNotificationService() : this(new DataService()) { } public void SendLeafWebComplete(int leafInputId) { var leafInput = _dataService.GetLeafInput(leafInputId); if (leafInput.CurrentStatus != LeafInputStatusType.Complete) { var notComplete = "Attempting to SendLeafWebComplete when status is not complete" + $" for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}"; Logger.Error(notComplete); throw new ArgumentException(notComplete); } var outputErrorMessage = leafInput.OutputErrorMessage; if (outputErrorMessage != null) SendLeafWebError(leafInput, outputErrorMessage.FileContents.Contents.GetString()); else SendLeafWebSuccess(leafInput); } public void SendLeafWebCancelled(int leafInputId) { var leafInput = _dataService.GetLeafInput(leafInputId); if (leafInput.CurrentStatus != LeafInputStatusType.Cancelled) { var notComplete = "Attempting to SendLeafWebCancelled when status is not complete " + $"for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}"; Logger.Error(notComplete); throw new ArgumentException(notComplete); } var body = $"Your leaf analysis job, {leafInput.Identifier}, has been cancelled. " + "Contact the administrator with any questions."; var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailCancelledSubject, leafInput), body); SendMessage(message); } public void SendAdministratorMessage(string subject, string body) { var message = new MailMessage(_emailFromAddress, _adminEmailAddresses, subject, body); SendMessage(message); } private void SendLeafWebSuccess(LeafInput leafInput) { var body = $"Your leaf analysis job, {leafInput.Identifier}, has completed. "; body += FormatWarningMessage(leafInput); var downloadLink = true; if (downloadLink) { var downloadUrl = _downloadUrlService.GetDownloadUrl(leafInput); body += "Download results with the following link:" + Environment.NewLine + Environment.NewLine + downloadUrl; var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailSuccessSubject, leafInput), body); SendMessage(message); } else { body += "Please see the attached results."; var message = new MailMessage(_emailFromAddress, leafInput.Email, EmailSuccessSubject, body); var fileStreams = (from outputFile in leafInput.OutputFiles select Tuple.Create(outputFile, new MemoryStream(outputFile.FileContents.Contents))).ToList(); try { foreach (var fileStream in fileStreams) { var attachment = new Attachment(fileStream.Item2, fileStream.Item1.Filename); message.Attachments.Add(attachment); } SendMessage(message); } finally { // can't dispose those memory streams until the message is sent foreach (var stream in fileStreams.Select(f => f.Item2)) { stream.Dispose(); } } } } private void SendLeafWebError(LeafInput leafInput, string errorMessage) { var body = $"Your leaf analysis job, {leafInput.Identifier}, encountered the following errors." + Environment.NewLine + Environment.NewLine + Environment.NewLine + errorMessage + Environment.NewLine + Environment.NewLine + "You will need to correct your input and resubmit."; body += FormatWarningMessage(leafInput); var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailErrorSubject, leafInput), body); SendMessage(message); } public void SendLeafWebSystemException(string leafInputIdentifier, string leafInputEmail) { var body = $"A system error occured while processing your leaf analysis job, {leafInputIdentifier}." + Environment.NewLine + "System administrators have been notified. You will be notified again when the system error " + "has been resolved and your data has been processed."; var message = new MailMessage(_emailFromAddress, leafInputEmail, EmailSystemErrorSubject, body); SendMessage(message); } private string FormatWarningMessage(LeafInput leafInput) { if (leafInput.OutputWarningMessage != null) return Environment.NewLine + Environment.NewLine + "The following warning message was generated." + Environment.NewLine + Environment.NewLine + leafInput.OutputWarningMessage.FileContents.Contents.GetString() + Environment.NewLine; return string.Empty; } private void SendMessage(MailMessage mailMessage) { try { Logger.Info($"Email sending to {mailMessage.To}, subject: {mailMessage.Subject}"); _smtpClient.Send(mailMessage); } catch (SmtpException ex) { Logger.Error($"Failed to send mail: {ex.Message}", ex); } } public void Dispose() { _dataService.Dispose(); } } }