private EmailQueueItem PanelActionEmail(ActionType actionType, string[] cc, string[] bcc, bool isHtml) { var emailType = "PanelAction_" + actionType; var template = _templateService.GetTemplate(emailType); if (template == null) { template = _templateService.GetTemplate("PanelAction"); if (template == null) { return(null); } } var queue = new EmailQueueItem { IsBodyHtml = isHtml, From = template.From, Subject = template.Subject, Body = template.Body, Priority = (short)template.Priority, CreatedOn = DateTime.Now }; _templateService.PopulateHeaders(queue, null, cc, bcc, isHtml); return(queue); }
/// <summary> /// Retrieves attachments for an EmailQueueItem /// </summary> /// <param name="item">The item to get attachments for</param> /// <returns></returns> public Attachment[] GetAttachments(EmailQueueItem item) { if (item == null) { throw new ArgumentNullException("item"); } TroutLog.Log.Info(string.Format("Retrieving attachments for email {0}", item.ID)); List <Attachment> attachments = new List <Attachment>(); if (!Directory.Exists(GetAttachmentDirectory(item))) { return(attachments.ToArray()); } var attachmentDirectories = Directory.EnumerateDirectories(GetAttachmentDirectory(item)); foreach (var attachmentDirectory in attachmentDirectories) { var files = Directory.EnumerateFiles(attachmentDirectory); if (files.Any()) { attachments.Add(new Attachment(files.First())); } } TroutLog.Log.Info(string.Format("Retrieved {0} attachments for email {1}", attachments.Count, item.ID)); return(attachments.ToArray()); }
public ActionConfirmation Queue(EmailQueueItem item) { try { if (item.IsValid()) { _queueRepository.SaveOrUpdate(item); _queueRepository.DbContext.CommitChanges(); var saveOrUpdateConfirmation = ActionConfirmation.CreateSuccess("The emails were successfully queued."); saveOrUpdateConfirmation.Value = item; return(saveOrUpdateConfirmation); } else { _queueRepository.DbContext.RollbackTransaction(); return (ActionConfirmation.CreateFailure( "The item could not be queued due to missing or invalid information")); } } catch (Exception exception) { return (ActionConfirmation.CreateFailure( "The email could not be saved due to missing or invalid information > " + exception.Message)); } }
private MailMessage GetMailMessage(EmailQueueItem message, OverrideList overrides) { var mailMessage = new MailMessage(); mailMessage.From = Config.FromAddress; if (!string.IsNullOrWhiteSpace(message.To)) { mailMessage.To.Add(message.To); } if (!string.IsNullOrWhiteSpace(message.Cc)) { mailMessage.CC.Add(message.Cc); } if (!string.IsNullOrWhiteSpace(message.Bcc)) { mailMessage.Bcc.Add(message.Bcc); } mailMessage.Subject = message.Subject; mailMessage.Body = message.Body; mailMessage.IsBodyHtml = message.IsBodyHtml; mailMessage = StaticOverridesesProvider.StaticOverrides.ApplyOverrides(mailMessage); mailMessage = overrides.ApplyOverrides(mailMessage); return(mailMessage); }
/// <summary> /// Saves attachments on the provided MailMessage based on values in the EmailQueueItem /// </summary> /// <param name="item">EmailQueueItem that attachments are to be saved on</param> /// <param name="mailMessage">MailMessage which contains attachments</param> public void SaveAttachments(EmailQueueItem item, MailMessage mailMessage) { if (item == null) { throw new ArgumentNullException("item"); } if (mailMessage == null) { throw new ArgumentNullException("mailMessage"); } TroutLog.Log.Info(string.Format("Saving {0} attachments for email {1}", mailMessage.Attachments.Count, item.ID)); for (int i = 0; i < mailMessage.Attachments.Count; i++) { var attachment = mailMessage.Attachments[i]; Directory.CreateDirectory(GetAttachmentDirectory(item, i)); using (FileStream file = new FileStream(GetAttachmentFileName(item, i, attachment), FileMode.OpenOrCreate, FileAccess.ReadWrite)) { byte[] buffer = new byte[attachment.ContentStream.Length]; attachment.ContentStream.Read(buffer, 0, buffer.Length); file.Write(buffer, 0, buffer.Length); } } TroutLog.Log.Info(string.Format("Saved {0} attachments for email {1}", mailMessage.Attachments.Count, item.ID)); }
/// <summary> /// Constructor /// </summary> /// <param name="emailQueueItem"></param> /// <param name="isSuccess"></param> /// <param name="message"></param> /// <param name="sentMailMessage"></param> /// <param name="tries"></param> public DequeueResultItem(EmailQueueItem emailQueueItem, bool isSuccess, string message, MailMessage sentMailMessage, int tries) { EmailQueueItem = emailQueueItem; Tries = tries; SentMailMessage = sentMailMessage; Message = message; IsSuccess = isSuccess; }
private string GetAttachmentDirectory(EmailQueueItem item) { return(string.Format("{0}\\{1}t\\{2}t\\{3}\\", Config.AttachmentPath, (item.ID / 100000).ToString("000\0\0"), //123,456,789 -> 123400 (item.ID / 1000) % 100, //123,456,789 -> 56 item.ID)); }
private void PurgeAttachments(EmailQueueItem item) { if (!Directory.Exists(GetAttachmentDirectory(item))) { return; } TroutLog.Log.Info(string.Format("Purging attachments for email {0} attachments", item.ID)); Directory.Delete(GetAttachmentDirectory(item), true); }
public void Update(string id, EmailMessage message) { using (SqlEmailServiceContext configContext = new SqlEmailServiceContext(this.nameOrConnectionString)) { Guid itemID = new Guid(id); EmailQueueItem item = configContext.EmailQueueItems.FirstOrDefault(x => x.ID == itemID && x.SendDate == null); item.ErrorMessage = message.ErrorMessage; item.RetryAttempt = message.RetryAttempt; item.SendDate = message.SendDate; configContext.SaveChanges(); } }
public async Task Test_ForgotPassword_Succeeds() { // Arrange const int IpAddressInt = 0x2414188f; const string IpAddressString = "143.24.20.36"; const string ConfirmEmailUrl = "https://some.url"; // Set up HTTP context accessor var httpContextAccessor = TestHelpers.CreateHttpContextAccessor(IpAddressInt); // Set up user manager var mockUserManager = CreateMockUserManager(userIsConfirmed: true); // Set up email repository var otherUserEmail = new EmailQueueItem { To = "Other email address", Subject = "Reset password" }; var otherSubjectEmail = new EmailQueueItem { To = EmailAddress, Subject = "Other subject" }; var mockEmailRepository = new Mock<IEmailRepository>(MockBehavior.Strict); mockEmailRepository.Setup(e => e.AddToQueue(It.IsAny<ResetPassword>())); mockEmailRepository .Setup(e => e.GetRecent()) .Returns(new[] { otherUserEmail, otherSubjectEmail }); // Set up model var httpContext = new DefaultHttpContext(); var mockUrlHelper = CreateMockUrlHelper(httpContext, ConfirmEmailUrl); var model = new ForgotPasswordModel( httpContextAccessor, mockUserManager.Object, mockEmailRepository.Object) { PageContext = { HttpContext = httpContext }, Input = new ForgotPasswordModel.InputModel { Email = EmailAddress }, Url = mockUrlHelper.Object }; // Act var result = await model.OnPostAsync(); // Assert Assert.IsType<RedirectToPageResult>(result); Assert.Equal("./ForgotPasswordConfirmation", ((RedirectToPageResult)result).PageName); mockEmailRepository.Verify(p => p.AddToQueue( It.Is<ResetPassword>(e => e.To == EmailAddress && e.HtmlBody.Contains(ConfirmEmailUrl, StringComparison.Ordinal) && e.HtmlBody.Contains(IpAddressString, StringComparison.OrdinalIgnoreCase))), Times.Once); }
public async Task Send(IEnumerable<string> to, IEnumerable<string> cc, string @from, string emailTemplateId, Dictionary<string, string> mergeValues) { EmailQueueItem item = new EmailQueueItem { Cc = new List<string>(cc), EmailTemplateId = emailTemplateId, From = from, MergeData = mergeValues, To = new List<string>(to) }; await _queue.EnqueueAsync(item); }
public async Task Send(IEnumerable<string> to, IEnumerable<string> cc, string @from, string subject, string htmlBody, string textBody) { EmailQueueItem item = new EmailQueueItem { Cc = new List<string>(cc), From = from, To = new List<string>(to), Subject = subject, HtmlBody = htmlBody, TextBody = textBody }; await _queue.EnqueueAsync(item); }
public string Save(EmailMessage message) { using (SqlEmailServiceContext configContext = new SqlEmailServiceContext(this.nameOrConnectionString)) { EmailQueueItem item = new EmailQueueItem(); item.ID = Guid.NewGuid().ToCombGuid(); item.ErrorMessage = string.Empty; item.CreateDate = DateTime.UtcNow; item.Message = EmailMessage.Serialize(message); configContext.EmailQueueItems.Add(item); configContext.SaveChanges(); return(item.ID.ToStringValue()); } }
public async Task SendAsync(IEnumerable<string> to, IEnumerable<string> cc, string @from, string subject, string htmlBody, string textBody) { _logger?.Verbose("EmailQueueDispatcher - SendAsync with subject/body - {0}", subject); EmailQueueItem item = new EmailQueueItem { Cc = new List<string>(cc), From = from, To = new List<string>(to), Subject = subject, HtmlBody = htmlBody, TextBody = textBody }; await _queue.EnqueueAsync(item); }
public void ValidatorMustCaptureInvalidEmail() { var emailQueueItem = new EmailQueueItem { Sender = "test", Receiver = "*****@*****.**", Subject = "Title", Body = "Body" }; var validator = new EmailQueueItemValidator(); var results = validator.Validate(emailQueueItem); Assert.False(results.IsValid); Assert.StrictEqual("Sender", results.Errors[0].PropertyName); Assert.StrictEqual("'Sender' is not a valid email address.", results.Errors[0].ErrorMessage); }
public async Task SendAsync(IEnumerable<string> to, IEnumerable<string> cc, string @from, string emailTemplateId, Dictionary<string, string> mergeValues, TemplateSyntaxEnum templateSyntax = TemplateSyntaxEnum.Razor) { _logger?.Verbose("EmailQueueDispatcher - SendAsync with template - {0}", emailTemplateId); EmailQueueItem item = new EmailQueueItem { Cc = new List<string>(cc), EmailTemplateId = emailTemplateId, From = from, MergeData = mergeValues, To = new List<string>(to), TemplateSyntax = templateSyntax }; await _queue.EnqueueAsync(item); }
/// <summary> /// Enqueues a set of MailMessages to be sent /// </summary> /// <param name="messages"></param> public void EnqueueMessages(IEnumerable <MailMessage> messages) { if (messages == null) { throw new ArgumentNullException("messages"); } TroutLog.Log.Info(string.Format("Beginning queuing of {0} messages", messages.Count())); List <Tuple <EmailQueueItem, MailMessage> > createdMessages = new List <Tuple <EmailQueueItem, MailMessage> >(); foreach (var message in messages.Where(m => m != null)) { var emailQueueItem = new EmailQueueItem() { To = message.To.ToString(), Cc = message.CC.ToString(), Bcc = message.Bcc.ToString(), Subject = message.Subject, Body = message.Body, CreateDate = DateTime.Now, IsSent = false, NumberTries = 0, LastTryDate = null, SendDate = null, IsBodyHtml = true, AttachmentCount = (byte)message.Attachments.Count }; createdMessages.Add(new Tuple <EmailQueueItem, MailMessage>(emailQueueItem, message)); Repository.Add(emailQueueItem); } Repository.SaveChanges(); foreach (var createdMessage in createdMessages) { if (createdMessage.Item1.AttachmentCount > 0) { AttachmentFileSystem.SaveAttachments(createdMessage.Item1, createdMessage.Item2); } TroutLog.Log.Info(string.Format("{0} was queued", createdMessage.Item1.ID)); } }
/// <summary> /// Sends an email to the specified email(s) using this template and the merge data provided. /// Use comma to separate multiple emails. /// </summary> public void Send(string to, object mergeData, Action<EmailQueueItem> customise = null) { if (mergeData == null) throw new ArgumentNullException("mergeData"); if (to.IsEmpty()) throw new ArgumentNullException("to"); var message = new EmailQueueItem { Html = true, Subject = this.MergeSubject(mergeData), Body = this.MergeBody(mergeData), To = to, }; if (customise != null) customise(message); Database.Save(message); }
protected override bool ParseArguments(string[] args) { OptionSet optionSet = new OptionSet().Add("id=", (int v) => EmailID = v); try { optionSet.Parse(args); } catch (OptionException) { Console.WriteLine("Error"); return(false); } Email = Repository.First(e => e.ID == EmailID); return(Email != null); }
public EmailMessage Get(string id) { using (SqlEmailServiceContext configContext = new SqlEmailServiceContext(this.nameOrConnectionString)) { Guid itemID = new Guid(id); EmailQueueItem item = configContext.EmailQueueItems.FirstOrDefault(x => x.ID == itemID && x.SendDate == null); if (item != null) { EmailMessage message = EmailMessage.Deserialize(item.Message); message.ErrorMessage = item.ErrorMessage; message.SendDate = item.SendDate; message.RetryAttempt = item.RetryAttempt; return(message); } } return(null); }
private static MailMessage CreateEmailMessageFromQueue(EmailQueueItem email) { var message = new MailMessage { From = new MailAddress(email.From), Priority = (MailPriority)email.Priority, IsBodyHtml = email.IsBodyHtml, Subject = email.Subject, Body = email.Body, BodyEncoding = email.BodyEncoding }; var toArray = email.To.Split(';'); foreach (var t in toArray) { message.To.Add(t); } return(message); }
public void PopulateHeadersToHtmlEmail(EmailQueueItem email, string to, string[] cc, string[] bcc) { email.IsBodyHtml = true; var bodyStyle = "bgcolor=\"#F8F8F8\" style=\"font-variant: normal; font-weight: normal; font-size: 12px; margin: 0; background-repeat: repeat-x; background-color: #F8F8F8; line-height: 17px; font-family: 'Lucida Grande' , 'Lucida Sans Unicode', Verdana, sans-serif; padding: 0; text-align: center; font-style: normal;\""; email.Body = $"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head><body {bodyStyle}>{FormatEmail(email.Body.Trim())}</body></html>"; if (!string.IsNullOrEmpty(to)) { email.To = to; } if (cc != null) { email.Cc = cc.ToDelimitedString(","); } if (bcc != null) { email.Bcc = bcc.ToDelimitedString(","); } }
public void PopulateHeaders(EmailQueueItem email, string to, string[] cc, string[] bcc, bool isHtml) { if (isHtml) { email.IsBodyHtml = true; email.Body = $"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head><body>{FormatPlainTextAsHtml(email.Body).Trim()}</body></html>"; } if (!string.IsNullOrEmpty(to)) { email.To = to; } if (cc != null) { email.Cc = cc.ToDelimitedString(","); } if (bcc != null) { email.Bcc = bcc.ToDelimitedString(","); } }
/// <summary> /// Sends an email to all the specified users using this template and the merge data provided. /// </summary> public void Send(IEnumerable<User> toUsers, object mergeData, Action<EmailQueueItem> customise = null) { if (mergeData == null) throw new ArgumentNullException("mergeData"); if (toUsers.None()) throw new ArgumentNullException("toUsers"); var emails = new List<EmailQueueItem>(); foreach (var email in toUsers.Select(u => u.Email)) { var message = new EmailQueueItem { Html = true, Subject = this.MergeSubject(mergeData), Body = this.MergeBody(mergeData), To = email, }; if (customise != null) customise(message); emails.Add(message); } Database.Save(emails); }
public Attachment[] GetAttachments(EmailQueueItem item) { return(Attachments.ContainsKey(item) ? Attachments[item] : new Attachment[0]); }
public void SaveAttachments(EmailQueueItem item, MailMessage mailMessage) { Attachments[item] = mailMessage.Attachments.ToArray(); }
public static async Task Test_SendPending() { // Arrange var unsentEmail = new EmailQueueItem { To = "[email protected]", Subject = "Unsent email subject", HtmlBody = "<p>Unsent email body</p>", PlainTextBody = "Unsent email body" }; var otherUnsentEmail = new EmailQueueItem { To = "[email protected]", Subject = "Other unsent email subject", HtmlBody = "<p>Other unsent email body</p>", PlainTextBody = "Other unsent email body" }; var unsentEmails = new[] { unsentEmail, otherUnsentEmail }; var mockEmailRepository = new Mock <IEmailRepository>(MockBehavior.Strict); mockEmailRepository .Setup(r => r.GetUnsent()) .Returns(unsentEmails); mockEmailRepository .Setup(r => r.MarkAsSent(It.IsAny <EmailQueueItem>())); var disabledMockEmailSender = new Mock <IEmailSender>(MockBehavior.Strict); disabledMockEmailSender .SetupGet(s => s.CanSend) .Returns(false); var enabledMockEmailSender = new Mock <IEmailSender>(MockBehavior.Strict); enabledMockEmailSender .SetupGet(s => s.CanSend) .Returns(true); enabledMockEmailSender .Setup(s => s.Send(It.IsAny <IEmailTemplate>())) .Returns(Task.CompletedTask); // Act var emailProcessor = new EmailProcessor( mockEmailRepository.Object, new[] { disabledMockEmailSender.Object, enabledMockEmailSender.Object }, Mock.Of <ILogger <EmailProcessor> >()); await emailProcessor.SendPending(); // Assert foreach (var emailQueueItem in unsentEmails) { enabledMockEmailSender.Verify( s => s.Send(It.Is <IEmailTemplate>(e => e.To == emailQueueItem.To && e.Subject == emailQueueItem.Subject && e.HtmlBody == emailQueueItem.HtmlBody && e.PlainTextBody == emailQueueItem.PlainTextBody)), Times.Once); mockEmailRepository.Verify( r => r.MarkAsSent(emailQueueItem), Times.Once); } }
private string GetAttachmentDirectory(EmailQueueItem item, int attachmentIndex) { return(string.Format("{0}\\{1}a\\", GetAttachmentDirectory(item), attachmentIndex)); }
/// <summary> /// Constructor /// </summary> /// <param name="emailQueueItem"></param> /// <param name="message"></param> public DequeueListItem(EmailQueueItem emailQueueItem, MailMessage message) { EmailQueueItem = emailQueueItem; Message = message; }
private string GetAttachmentFileName(EmailQueueItem item, int attachmentIndex, Attachment attachment) { return(string.Format("{0}\\{1}", GetAttachmentDirectory(item, attachmentIndex), attachment.Name)); }
public async Task RunAsync([QueueTrigger("email-items", Connection = "EmailServiceStorageCS")] EmailQueueItem emailQueueItem, [DurableClient] IDurableEntityClient client) { var stopWatch = Stopwatch.StartNew(); using (SentrySdk.Init(_configOptions.Value.Sentry.Dsn)) { var entityId = new EntityId(nameof(EmailProvidersStatus), "emailproviderstatus"); var entity = await client.ReadEntityStateAsync <EmailProvidersStatus>(entityId); await client.SignalEntityAsync <IEmailProvidersStatus>(entityId, s => s.Init()); string providerToUse; // Entity doesn't exist yet, take the first supported provider if (!entity.EntityExists) { providerToUse = _configOptions.Value.EmailProvidersSettings.SupportedProviders.FirstOrDefault(); } else { providerToUse = await entity.EntityState.Get(); } if (string.IsNullOrEmpty(providerToUse)) { throw new Exception("No Email Providers were found, maybe all providers are disabled because there are unhealthy!. Using retries.."); } using (LogContext.PushProperty("EmailProvider", providerToUse)) using (LogContext.PushProperty("Receiver", emailQueueItem.Receiver)) { try { var validator = new EmailQueueItemValidator(); var validationResults = await validator.ValidateAsync(emailQueueItem); if (!validationResults.IsValid) { var errorMessage = validationResults.Errors .Select(ve => $"{ve.PropertyName} {ve.ErrorMessage}") .Aggregate("", (acc, curr) => $"{acc}\n{curr}"); _logger.LogError(errorMessage, emailQueueItem); _logger.LogError("The provided queue item is invalid and will be skipped"); } else { await _emailProviders[providerToUse].SendEmail(emailQueueItem.Sender, emailQueueItem.Receiver, emailQueueItem.Subject, emailQueueItem.Body); } } catch (Exception ex) { // Capture the exception and send it to Sentry, then rethrow it to retry executing it. SentrySdk.CaptureException(ex); await client.SignalEntityAsync(entityId, "AddFailure", new FailureRequest { ProviderName = providerToUse, HappenedAt = DateTimeOffset.UtcNow }); throw ex; } finally { stopWatch.Stop(); _logger.LogInformation($"The request processing time was {stopWatch.ElapsedMilliseconds}"); _logger.LogInformation($"C# Queue trigger function processed: {JsonConvert.SerializeObject(emailQueueItem)}"); } } } }