/// <summary> /// Gets the HTML preview. /// </summary> /// <param name="communication">The communication.</param> /// <param name="person">The person.</param> /// <returns></returns> public override string GetHtmlPreview(Model.Communication communication, Person person) { var rockContext = new RockContext(); // Requery the Communication object communication = new CommunicationService(rockContext).Get(communication.Id); var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); var mergeValues = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(null); if (person != null) { mergeValues.Add("Person", person); var recipient = communication.Recipients.Where(r => r.PersonAlias != null && r.PersonAlias.PersonId == person.Id).FirstOrDefault(); if (recipient != null) { // Add any additional merge fields created through a report foreach (var mergeField in recipient.AdditionalMergeValues) { if (!mergeValues.ContainsKey(mergeField.Key)) { mergeValues.Add(mergeField.Key, mergeField.Value); } } } } string message = communication.GetMediumDataValue("Message"); return(message.ResolveMergeFields(mergeValues)); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> public override void Send(Model.Communication communication) { var rockContext = new RockContext(); var communicationService = new CommunicationService(rockContext); communication = communicationService.Get(communication.Id); if (communication != null && communication.Status == Model.CommunicationStatus.Approved && communication.Recipients.Where(r => r.Status == Model.CommunicationRecipientStatus.Pending).Any() && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { // Update any recipients that should not get sent the communication var recipientService = new CommunicationRecipientService(rockContext); foreach (var recipient in recipientService.Queryable("PersonAlias.Person") .Where(r => r.CommunicationId == communication.Id && r.Status == CommunicationRecipientStatus.Pending) .ToList()) { var person = recipient.PersonAlias.Person; if (person.IsDeceased ?? false) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Person is deceased!"; } } rockContext.SaveChanges(); } base.Send(communication); }
/// <summary> /// Sends the asynchronous. /// </summary> /// <param name="communication">The communication.</param> public virtual async Task SendAsync(Model.Communication communication) { if (this.IsActive) { // Get the Medium's Entity Type Id int mediumEntityTypeId = EntityTypeCache.Get(this.GetType()).Id; // Add the Medium's settings as attributes for the Transport to use. var mediumAttributes = GetMediumAttributes(); // Use the transport to send communication var transport = Transport; if (transport != null && transport.IsActive) { var asyncTransport = transport as IAsyncTransport; if (asyncTransport == null) { transport.Send(communication, mediumEntityTypeId, mediumAttributes); } else { await asyncTransport.SendAsync(communication, mediumEntityTypeId, mediumAttributes).ConfigureAwait(false); } } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> public virtual void Send(Model.Communication communication) { if (this.IsActive) { // Get the Medium's Entity Type Id int mediumEntityTypeId = EntityTypeCache.Read(this.GetType()).Id; // Add the Medium's settings as attributes for the Transport to use. var mediumAttributes = new Dictionary <string, string>(); foreach (var attr in this.Attributes.Select(a => a.Value)) { string value = this.GetAttributeValue(attr.Key); if (value.IsNotNullOrWhitespace()) { mediumAttributes.Add(attr.Key, GetAttributeValue(attr.Key)); } } // Use the transport to send communication var transport = Transport; if (transport != null && transport.IsActive) { transport.Send(communication, mediumEntityTypeId, mediumAttributes); } } }
private async Task SendToCommunicationRecipient(Model.Communication communication, string fromPhone, Dictionary <string, object> mergeFields, Person currentPerson, List <Uri> attachmentMediaUrls, int personEntityTypeId, int communicationCategoryId, int communicationEntityTypeId, string publicAppRoot, string callbackUrl, CommunicationRecipient recipient) { using (var rockContext = new RockContext()) { try { recipient = new CommunicationRecipientService(rockContext).Get(recipient.Id); var twilioNumber = recipient.PersonAlias.Person.PhoneNumbers.GetFirstSmsNumber(); if (!string.IsNullOrWhiteSpace(twilioNumber)) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var response = await SendToTwilioAsync(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber).ConfigureAwait(false); recipient.Status = CommunicationRecipientStatus.Delivered; recipient.SendDateTime = RockDateTime.Now; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.Sid; try { var historyService = new HistoryService(rockContext); historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Verb = History.HistoryVerb.Sent.ConvertToString().ToUpper(), ChangeType = History.HistoryChangeType.Record.ToString(), ValueName = "SMS message", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } else { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No Phone Number with Messaging Enabled"; } } catch (Exception ex) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Twilio Exception: " + ex.Message; } rockContext.SaveChanges(); } }
/// <summary> /// Gets the read-only message details. /// </summary> /// <param name="communication">The communication.</param> /// <returns></returns> public override string GetMessageDetails(Model.Communication communication) { StringBuilder sb = new StringBuilder(); AppendMediumData(communication, sb, "FromValue"); AppendMediumData(communication, sb, "Message"); return(sb.ToString()); }
private void AppendMediumData(Model.Communication communication, StringBuilder sb, string key) { string value = communication.GetMediumDataValue(key); if (!string.IsNullOrWhiteSpace(value)) { AppendMediumData(sb, key, value); } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> public virtual void Send(Model.Communication communication) { if (this.IsActive) { // Get the Medium's Entity Type Id int mediumEntityTypeId = EntityTypeCache.Get(this.GetType()).Id; // Add the Medium's settings as attributes for the Transport to use. var mediumAttributes = GetMediumAttributes(); // Use the transport to send communication if (Transport != null && Transport.IsActive) { Transport.Send(communication, mediumEntityTypeId, mediumAttributes); } } }
private RockEmailMessage GetTemplateRockEmailMessage(Model.Communication communication, Dictionary <string, object> mergeFields, GlobalAttributesCache globalAttributes) { var resultEmailMessage = new RockEmailMessage(); var publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false; resultEmailMessage.AppRoot = publicAppRoot; resultEmailMessage.CssInliningEnabled = cssInliningEnabled; resultEmailMessage.CurrentPerson = communication.CreatedByPersonAlias?.Person; resultEmailMessage.EnabledLavaCommands = communication.EnabledLavaCommands; resultEmailMessage.FromEmail = communication.FromEmail; resultEmailMessage.FromName = communication.FromName; var fromAddress = GetFromAddress(resultEmailMessage, mergeFields, globalAttributes); var fromName = GetFromName(resultEmailMessage, mergeFields, globalAttributes); resultEmailMessage.FromEmail = fromAddress; resultEmailMessage.FromName = fromName; // Reply To var replyToEmail = ""; if (communication.ReplyToEmail.IsNotNullOrWhiteSpace()) { // Resolve any possible merge fields in the replyTo address replyToEmail = communication.ReplyToEmail.ResolveMergeFields(mergeFields, resultEmailMessage.CurrentPerson); } resultEmailMessage.ReplyToEmail = replyToEmail; // Attachments resultEmailMessage.Attachments = communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile).ToList(); // Load up the content stream while the context is still active. for (int i = 0; i < resultEmailMessage.Attachments.Count; i++) { var _ = resultEmailMessage.Attachments[i].ContentStream; } return(resultEmailMessage); }
/// <summary> /// Gets the read-only message details. /// </summary> /// <param name="communication">The communication.</param> /// <returns></returns> public override string GetMessageDetails(Model.Communication communication) { StringBuilder sb = new StringBuilder(); sb.AppendLine("<div class='row'>"); sb.AppendLine("<div class='col-md-6'>"); AppendMediumData(communication, sb, "FromName"); AppendMediumData(communication, sb, "FromAddress"); AppendMediumData(communication, sb, "ReplyTo"); AppendMediumData(communication, sb, "Subject"); sb.AppendLine("</div>"); sb.AppendLine("<div class='col-md-6'>"); AppendAttachmentData(sb, communication.GetMediumDataValue("Attachments")); sb.AppendLine("</div>"); sb.AppendLine("</div>"); string value = communication.GetMediumDataValue("HtmlMessage"); if (!string.IsNullOrWhiteSpace(value)) { AppendMediumData(sb, "HtmlMessage", string.Format(@" <iframe id='js-email-body-iframe' class='email-body'></iframe> <script id='email-body' type='text/template'>{0}</script> <script type='text/javascript'> var doc = document.getElementById('js-email-body-iframe').contentWindow.document; doc.open(); doc.write('<html><head><title></title></head><body>' + $('#email-body').html() + '</body></html>'); doc.close(); </script> ", value)); } AppendMediumData(communication, sb, "TextMessage"); return(sb.ToString()); }
/// <summary> /// Sends the communication asynchronous. /// </summary> /// <param name="comm">The comm.</param> /// <param name="mutex">The mutex.</param> /// <returns></returns> private async Task <SendCommunicationAsyncResult> SendCommunicationAsync(Model.Communication comm, SemaphoreSlim mutex) { var communicationResult = new SendCommunicationAsyncResult { Communication = comm }; var communicationStopWatch = Stopwatch.StartNew(); RockLogger.Log.Debug(RockLogDomains.Jobs, "{0}: Starting to send {1}.", nameof(SendCommunicationAsync), comm.Name); try { await Model.Communication.SendAsync(comm).ConfigureAwait(false); } catch (Exception ex) { communicationResult.Exception = ex; } RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: {1} took {2} ms", nameof(SendCommunications), comm.Name, communicationStopWatch.ElapsedMilliseconds); mutex.Release(); return(communicationResult); }
public override void Send(Model.Communication communication) { int mediumEntityId = EntityTypeCache.Get(Rock.SystemGuid.EntityType.COMMUNICATION_MEDIUM_EMAIL.AsGuid())?.Id ?? 0; Send(communication, mediumEntityId, null); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext).Get(communication.Id); bool hasPendingRecipients; if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); hasPendingRecipients = qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any(); } else { hasPendingRecipients = false; } if (hasPendingRecipients) { var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); string fromPhone = communication.SMSFromDefinedValue?.Value; if (string.IsNullOrWhiteSpace(fromPhone)) { // just in case we got this far without a From Number, throw an exception throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString()); } if (!string.IsNullOrWhiteSpace(fromPhone)) { int?throttlingWaitTimeMS = null; if (this.IsLongCodePhoneNumber(fromPhone)) { throttlingWaitTimeMS = this.GetAttributeValue("Long-CodeThrottling").AsIntegerOrNull(); } string accountSid = GetAttributeValue("SID"); string authToken = GetAttributeValue("Token"); TwilioClient.Init(accountSid, authToken); var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryId = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id; string callbackUrl = publicAppRoot + "Webhooks/Twilio.ashx"; var smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS); List <Uri> attachmentMediaUrls = new List <Uri>(); if (smsAttachmentsBinaryFileIdList.Any()) { attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(communicationRockContext).GetByIds(smsAttachmentsBinaryFileIdList)); } bool recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipientRockContext = new RockContext(); var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); if (recipient != null) { if (ValidRecipient(recipient, communication.IsBulkCommunication)) { try { var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers .Where(p => p.IsMessagingEnabled) .FirstOrDefault(); if (phoneNumber != null) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); string twilioNumber = phoneNumber.Number; if (!string.IsNullOrWhiteSpace(phoneNumber.CountryCode)) { twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number; } MessageResource response = SendToTwilio(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber); recipient.Status = CommunicationRecipientStatus.Delivered; recipient.SendDateTime = RockDateTime.Now; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.Sid; try { var historyService = new HistoryService(recipientRockContext); historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Verb = History.HistoryVerb.Sent.ConvertToString().ToUpper(), ChangeType = History.HistoryChangeType.Record.ToString(), ValueName = "SMS message", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } else { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No Phone Number with Messaging Enabled"; } } catch (Exception ex) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Twilio Exception: " + ex.Message; } } recipientRockContext.SaveChanges(); if (throttlingWaitTimeMS.HasValue) { System.Threading.Tasks.Task.Delay(throttlingWaitTimeMS.Value).Wait(); } } else { recipientFound = false; } } } } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable().Include(a => a.CreatedByPersonAlias.Person).Include(a => a.CommunicationTemplate) .FirstOrDefault(c => c.Id == communication.Id); // If there are no pending recipients than just exit the method if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); if (!qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any()) { return; } } var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false; string fromAddress = string.IsNullOrWhiteSpace(communication.FromEmail) ? globalAttributes.GetValue("OrganizationEmail") : communication.FromEmail; string fromName = string.IsNullOrWhiteSpace(communication.FromName) ? globalAttributes.GetValue("OrganizationName") : communication.FromName; // Resolve any possible merge fields in the from address fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); fromName = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); Parameter replyTo = new Parameter(); // Reply To if (communication.ReplyToEmail.IsNotNullOrWhiteSpace()) { // Resolve any possible merge fields in the replyTo address replyTo.Name = "h:Reply-To"; replyTo.Type = ParameterType.GetOrPost; replyTo.Value = communication.ReplyToEmail.ResolveMergeFields(mergeFields, currentPerson); } var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(); RestRequest restRequest = null; // Loop through recipients and send the email bool recipientFound = true; while (recipientFound) { var recipientRockContext = new RockContext(); var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); // This means we are done, break the loop if (recipient == null) { recipientFound = false; break; } // Not valid save the obj with the status messages then go to the next one if (!ValidRecipient(recipient, communication.IsBulkCommunication)) { recipientRockContext.SaveChanges(); continue; } try { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); // Create the request obj restRequest = new RestRequest(GetAttributeValue("Resource"), Method.POST); restRequest.AddParameter("domian", GetAttributeValue("Domain"), ParameterType.UrlSegment); // ReplyTo if (communication.ReplyToEmail.IsNotNullOrWhiteSpace()) { restRequest.AddParameter(replyTo); } // From restRequest.AddParameter("from", new MailAddress(fromAddress, fromName).ToString()); // To restRequest.AddParameter("to", new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName).ToString()); // Safe sender checks CheckSafeSender(restRequest, fromAddress, globalAttributes.GetValue("OrganizationEmail")); // CC if (communication.CCEmails.IsNotNullOrWhiteSpace()) { string[] ccRecipients = communication.CCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(','); foreach (var ccRecipient in ccRecipients) { restRequest.AddParameter("cc", ccRecipient); } } // BCC if (communication.BCCEmails.IsNotNullOrWhiteSpace()) { string[] bccRecipients = communication.BCCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(','); foreach (var bccRecipient in bccRecipients) { restRequest.AddParameter("bcc", bccRecipient); } } // Subject string subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); restRequest.AddParameter("subject", subject); // Body Plain Text if (mediumAttributes.ContainsKey("DefaultPlainText")) { string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); if (!string.IsNullOrWhiteSpace(plainText)) { AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new ContentType(MediaTypeNames.Text.Plain)); restRequest.AddParameter("text", plainTextView); } } // Body HTML string htmlBody = communication.Message; // Get the unsubscribe content and add a merge field for it if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML")) { string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml); htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); // Resolve special syntax needed if option was included in global attribute if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]")) { htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml); } // Add the unsubscribe option at end if it wasn't included in content if (!htmlBody.Contains(unsubscribeHtml)) { htmlBody += unsubscribeHtml; } } else { htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty); } if (!string.IsNullOrWhiteSpace(htmlBody)) { if (cssInliningEnabled) { // move styles inline to help it be compatible with more email clients htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes(); } // add the main Html content to the email restRequest.AddParameter("html", htmlBody); } // Headers AddAdditionalHeaders(restRequest, new Dictionary <string, string>() { { "communication_recipient_guid", recipient.Guid.ToString() } }); // Attachments foreach (var attachment in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile)) { MemoryStream ms = new MemoryStream(); attachment.ContentStream.CopyTo(ms); restRequest.AddFile("attachment", ms.ToArray(), attachment.FileName); } // Send the email // Send it RestClient restClient = new RestClient { BaseUrl = new Uri(GetAttributeValue("BaseURL")), Authenticator = new HttpBasicAuthenticator("api", GetAttributeValue("APIKey")) }; // Call the API and get the response Response = restClient.Execute(restRequest); // Update recipient status and status note recipient.Status = Response.StatusCode == HttpStatusCode.OK ? CommunicationRecipientStatus.Delivered : CommunicationRecipientStatus.Failed; recipient.StatusNote = Response.StatusDescription; recipient.TransportEntityTypeName = this.GetType().FullName; // Log it try { var historyChangeList = new History.HistoryChangeList(); historyChangeList.AddChange( History.HistoryVerb.Sent, History.HistoryChangeType.Record, $"Communication") .SetRelatedData(fromName, communicationEntityTypeId, communication.Id) .SetCaption(subject); HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } catch (Exception ex) { ExceptionLogService.LogException(ex); recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => "); } recipientRockContext.SaveChanges(); } } }
public override string GetMessageDetails(Model.Communication communication) { throw new NotSupportedException(); }
public override string GetHtmlPreview(Model.Communication communication, Person person) { throw new NotSupportedException(); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { AsyncHelper.RunSync(() => SendAsync(communication, mediumEntityTypeId, mediumAttributes)); }
/// <summary> /// Gets the HTML preview. /// </summary> /// <param name="communication">The communication.</param> /// <param name="person">The person.</param> /// <returns></returns> public override string GetHtmlPreview(Model.Communication communication, Person person) { var rockContext = new RockContext(); StringBuilder sbContent = new StringBuilder(); var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null); // Requery the Communication object communication = new CommunicationService(rockContext).Get(communication.Id); mergeFields.Add("Communication", communication); if (person != null) { mergeFields.Add("Person", person); var recipient = new CommunicationRecipientService(rockContext).Queryable().Where(a => a.CommunicationId == communication.Id).Where(r => r.PersonAlias != null && r.PersonAlias.PersonId == person.Id).FirstOrDefault(); if (recipient != null) { // Add any additional merge fields created through a report foreach (var mergeField in recipient.AdditionalMergeValues) { if (!mergeFields.ContainsKey(mergeField.Key)) { mergeFields.Add(mergeField.Key, mergeField.Value); } } } } // Body string htmlContent = communication.GetMediumDataValue("HtmlMessage"); sbContent.Append(Email.ProcessHtmlBody(communication, globalAttributes, mergeFields)); // Attachments StringBuilder sbAttachments = new StringBuilder(); string attachmentIds = communication.GetMediumDataValue("Attachments"); if (!string.IsNullOrWhiteSpace(attachmentIds)) { sbContent.Append("<br/><br/>"); var binaryFileService = new BinaryFileService(rockContext); foreach (string idVal in attachmentIds.SplitDelimitedValues()) { int binaryFileId = int.MinValue; if (int.TryParse(idVal, out binaryFileId)) { var binaryFile = binaryFileService.Get(binaryFileId); if (binaryFile != null) { sbContent.AppendFormat("<a target='_blank' href='{0}GetFile.ashx?id={1}'>{2}</a><br/>", System.Web.VirtualPathUtility.ToAbsolute("~"), binaryFile.Id, binaryFile.FileName); } } } } return(sbContent.ToString()); }
/// <summary> /// Sends the asynchronous. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public async Task SendAsync(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { var fromPhone = string.Empty; var unprocessedRecipientCount = 0; var mergeFields = new Dictionary <string, object>(); Person currentPerson = null; var attachmentMediaUrls = new List <Uri>(); var personEntityTypeId = 0; var communicationCategoryId = 0; var communicationEntityTypeId = 0; using (var rockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(rockContext).Get(communication.Id); if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(rockContext).Queryable(); unprocessedRecipientCount = qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Count(); } if (unprocessedRecipientCount == 0) { return; } fromPhone = communication.SMSFromDefinedValue?.Value; if (string.IsNullOrWhiteSpace(fromPhone)) { // just in case we got this far without a From Number, throw an exception throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString()); } currentPerson = communication.CreatedByPersonAlias?.Person; mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); personEntityTypeId = EntityTypeCache.Get <Person>().Id; communicationEntityTypeId = EntityTypeCache.Get <Model.Communication>().Id; communicationCategoryId = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext).Id; var smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS); if (smsAttachmentsBinaryFileIdList.Any()) { attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(rockContext).GetByIds(smsAttachmentsBinaryFileIdList)); } } int?throttlingWaitTimeMS = null; if (this.IsLongCodePhoneNumber(fromPhone)) { throttlingWaitTimeMS = GetAttributeValue(TwilioAttributeKey.LongCodeThrottling).AsIntegerOrNull(); } var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot"); var callbackUrl = publicAppRoot + "Webhooks/Twilio.ashx"; var accountSid = GetAttributeValue(TwilioAttributeKey.Sid); var authToken = GetAttributeValue(TwilioAttributeKey.AuthToken); TwilioClient.Init(accountSid, authToken); if (throttlingWaitTimeMS.HasValue) { // If throttlingWaitTime has a value we need to send all text synchronously so that the throttle is respected. var recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication); // This means we are done, break the loop if (recipient == null) { recipientFound = false; continue; } await SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient).ConfigureAwait(false); await Task.Delay(throttlingWaitTimeMS.Value).ConfigureAwait(false); } } else { var sendingTask = new List <Task>(unprocessedRecipientCount); var asyncTransport = this as IAsyncTransport; var maxParallelization = asyncTransport?.MaxParallelization ?? 10; using (var mutex = new SemaphoreSlim(maxParallelization)) { var recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication); // This means we are done, break the loop if (recipient == null) { recipientFound = false; continue; } await mutex.WaitAsync().ConfigureAwait(false); sendingTask.Add(ThrottleHelper.ThrottledExecute(() => SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient), mutex)); } /* * Now that we have fired off all of the task, we need to wait for them to complete. * Once all of the task have been completed we can continue. */ while (sendingTask.Count > 0) { var completedTask = await Task.WhenAny(sendingTask).ConfigureAwait(false); sendingTask.Remove(completedTask); } } } }
/// <summary> /// Sends the specified communication from the Communication Wizard in Rock. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable("CreatedByPersonAlias.Person") .FirstOrDefault(c => c.Id == communication.Id); bool hasPendingRecipients; if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); hasPendingRecipients = qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any(); } else { hasPendingRecipients = false; } if (hasPendingRecipients) { var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryId = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id; bool recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipientRockContext = new RockContext(); var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); if (recipient != null) { if (ValidRecipient(recipient, communication.IsBulkCommunication)) { if (recipient.PersonAliasId.HasValue) { try { var mergeObjects = recipient.CommunicationMergeValues(mergeFields); var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var title = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var sound = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var data = ResolveText(communication.PushData, currentPerson, communication.EnabledLavaCommands, mergeFields, publicAppRoot); var jsonData = Newtonsoft.Json.JsonConvert.DeserializeObject <PushData>(data); var url = jsonData.Url; string appId = GetAttributeValue("AppId"); string restApiKey = GetAttributeValue("RestAPIKey"); OneSignalClient client = new OneSignalClient(restApiKey); var options = new NotificationCreateOptions { AppId = new Guid(appId), IncludeExternalUserIds = new List <string> { recipient.PersonAliasId.ToString() } }; options.Headings.Add(LanguageCodes.English, title); options.Contents.Add(LanguageCodes.English, message); options.Url = url; NotificationCreateResult response = client.Notifications.Create(options); bool failed = !string.IsNullOrWhiteSpace(response.Error); var status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered; if (failed) { recipient.StatusNote = "OneSignal failed to notify devices"; } else { recipient.SendDateTime = RockDateTime.Now; } recipient.Status = status; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.Id; try { var historyService = new HistoryService(recipientRockContext); historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Verb = History.HistoryVerb.Sent.ConvertToString().ToUpper(), ChangeType = History.HistoryChangeType.Record.ToString(), ValueName = "Push Notification", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } catch (Exception ex) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "OneSignal Exception: " + ex.Message; } } } recipientRockContext.SaveChanges(); } else { recipientFound = false; } } } } }
public abstract string GetHtmlPreview(Model.Communication communication, Person person);
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> public override void Send(Model.Communication communication) { var rockContext = new RockContext(); var communicationService = new CommunicationService(rockContext); communication = communicationService.Queryable() .FirstOrDefault(t => t.Id == communication.Id); if (communication != null && communication.Status == Model.CommunicationStatus.Approved && communication.HasPendingRecipients(rockContext) && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { // Update any recipients that should not get sent the communication var recipientService = new CommunicationRecipientService(rockContext); foreach (var recipient in recipientService.Queryable("PersonAlias.Person") .Where(r => r.CommunicationId == communication.Id && r.Status == CommunicationRecipientStatus.Pending) .ToList()) { var person = recipient.PersonAlias.Person; if (!person.IsEmailActive) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Email is not active!"; } if (person.IsDeceased) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Person is deceased!"; } if (person.EmailPreference == Model.EmailPreference.DoNotEmail) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Email Preference of 'Do Not Email!'"; } else if (person.EmailPreference == Model.EmailPreference.NoMassEmails && communication.IsBulkCommunication) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Email Preference of 'No Mass Emails!'"; } } // If an unsubscribe value has been entered, and this is a bulk email, add the text if (communication.IsBulkCommunication) { string unsubscribeHtml = GetAttributeValue("UnsubscribeHTML"); if (!string.IsNullOrWhiteSpace(unsubscribeHtml)) { communication.SetMediumDataValue("UnsubscribeHTML", unsubscribeHtml); } } string defaultPlainText = GetAttributeValue("DefaultPlainText"); if (!string.IsNullOrWhiteSpace(defaultPlainText)) { communication.SetMediumDataValue("DefaultPlainText", defaultPlainText); } rockContext.SaveChanges(); } base.Send(communication); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { var pushData = communication.PushData.FromJsonOrNull <PushData>(); using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable("CreatedByPersonAlias.Person") .FirstOrDefault(c => c.Id == communication.Id); bool hasPendingRecipients; if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); hasPendingRecipients = qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any(); } else { hasPendingRecipients = false; } if (hasPendingRecipients) { var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot"); var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); string serverKey = GetAttributeValue("ServerKey"); var sender = new Sender(serverKey); var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryId = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id; bool recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipientRockContext = new RockContext(); var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); if (recipient != null) { if (ValidRecipient(recipient, communication.IsBulkCommunication)) { try { var siteId = pushData?.MobileApplicationId; List <string> devices = null; if (recipient.PersonAliasId.HasValue) { int personAliasId = recipient.PersonAliasId.Value; var service = new PersonalDeviceService(recipientRockContext); devices = service.Queryable() .Where(p => p.PersonAliasId.HasValue && p.PersonAliasId.Value == personAliasId && p.NotificationsEnabled && !string.IsNullOrEmpty(p.DeviceRegistrationId)) .Where(p => !siteId.HasValue || siteId.Value == p.SiteId) .Select(p => p.DeviceRegistrationId) .ToList(); } else if (!string.IsNullOrEmpty(recipient.PersonalDevice?.DeviceRegistrationId)) { devices = new List <string> { recipient.PersonalDevice?.DeviceRegistrationId }; } if (devices != null && devices.Any()) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var title = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var sound = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); var notification = new Message { RegistrationIds = devices.Distinct().ToList(), Notification = new FCM.Net.Notification { Title = title, Body = message, Sound = sound, }, Data = GetPushNotificationData(communication.PushOpenAction, pushData, recipient) }; ResponseContent response = Utility.AsyncHelpers.RunSync(() => sender.SendAsync(notification)); bool failed = response.MessageResponse.Failure == devices.Count || response.MessageResponse.Success == 0; var status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered; if (failed) { recipient.StatusNote = "Firebase failed to notify devices"; } else { recipient.SendDateTime = RockDateTime.Now; } recipient.Status = status; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.MessageResponse.MulticastId; if (recipient.PersonAlias != null) { try { var historyService = new HistoryService(recipientRockContext); historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Verb = History.HistoryVerb.Sent.ConvertToString().ToUpper(), ChangeType = History.HistoryChangeType.Record.ToString(), ValueName = "Push Notification", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } } else { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No Personal Devices with Messaging Enabled"; } } catch (Exception ex) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Firebase Exception: " + ex.Message; } } recipientRockContext.SaveChanges(); } else { recipientFound = false; } } } } }
private RockEmailMessage GetRecipientRockEmailMessage(RockEmailMessage emailMessage, Model.Communication communication, CommunicationRecipient communicationRecipient, Dictionary <string, object> mergeFields, string organizationEmail, Dictionary <string, string> mediumAttributes) { var recipientEmail = new RockEmailMessage(); recipientEmail.CurrentPerson = emailMessage.CurrentPerson; recipientEmail.EnabledLavaCommands = emailMessage.EnabledLavaCommands; recipientEmail.AppRoot = emailMessage.AppRoot; recipientEmail.CssInliningEnabled = emailMessage.CssInliningEnabled; // CC if (communication.CCEmails.IsNotNullOrWhiteSpace()) { string[] ccRecipients = communication .CCEmails .ResolveMergeFields(mergeFields, emailMessage.CurrentPerson) .Replace(";", ",") .Split(','); foreach (var ccRecipient in ccRecipients) { recipientEmail.CCEmails.Add(ccRecipient); } } // BCC if (communication.BCCEmails.IsNotNullOrWhiteSpace()) { string[] bccRecipients = communication .BCCEmails .ResolveMergeFields(mergeFields, emailMessage.CurrentPerson) .Replace(";", ",") .Split(','); foreach (var bccRecipient in bccRecipients) { recipientEmail.BCCEmails.Add(bccRecipient); } } // Attachments recipientEmail.Attachments = emailMessage.Attachments; // Communication record for tracking opens & clicks recipientEmail.MessageMetaData = new Dictionary <string, string>(emailMessage.MessageMetaData); // To var toEmailAddress = new RockEmailMessageRecipient(null, null) { To = communicationRecipient.PersonAlias.Person.Email, Name = communicationRecipient.PersonAlias.Person.FullName }; recipientEmail.SetRecipients(new List <RockEmailMessageRecipient> { toEmailAddress }); var fromMailAddress = new MailAddress(emailMessage.FromEmail, emailMessage.FromName); var checkResult = CheckSafeSender(new List <string> { toEmailAddress.EmailAddress }, fromMailAddress, organizationEmail); // Reply To recipientEmail.ReplyToEmail = GetRecipientReplyToAddress(emailMessage, mergeFields, checkResult); // From if (checkResult.IsUnsafeDomain && checkResult.SafeFromAddress != null) { recipientEmail.FromName = checkResult.SafeFromAddress.DisplayName; recipientEmail.FromEmail = checkResult.SafeFromAddress.Address; } else { recipientEmail.FromName = fromMailAddress.DisplayName; recipientEmail.FromEmail = fromMailAddress.Address; } // Subject var subject = ResolveText(communication.Subject, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot); recipientEmail.Subject = subject; // Body Plain Text if (mediumAttributes.ContainsKey("DefaultPlainText")) { var plainText = ResolveText(mediumAttributes["DefaultPlainText"], emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot); if (!string.IsNullOrWhiteSpace(plainText)) { recipientEmail.PlainTextMessage = plainText; } } // Body (HTML) string htmlBody = communication.Message; // Get the unsubscribe content and add a merge field for it if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML")) { string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot); mergeFields.AddOrReplace("UnsubscribeOption", unsubscribeHtml); htmlBody = ResolveText(htmlBody, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot); // Resolve special syntax needed if option was included in global attribute if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]")) { htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml); } // Add the unsubscribe option at end if it wasn't included in content if (!htmlBody.Contains(unsubscribeHtml)) { htmlBody += unsubscribeHtml; } } else { htmlBody = ResolveText(htmlBody, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot); htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty); } if (!string.IsNullOrWhiteSpace(htmlBody)) { if (emailMessage.CssInliningEnabled) { // move styles inline to help it be compatible with more email clients htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes(); } // add the main Html content to the email recipientEmail.Message = htmlBody; } recipientEmail.MessageMetaData["communication_recipient_guid"] = communicationRecipient.Guid.ToString(); return(recipientEmail); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public abstract void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes);
public abstract void Send(Model.Communication communication);
public abstract string GetMessageDetails(Model.Communication communication);
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable() .Include(a => a.CreatedByPersonAlias.Person) .Include(a => a.CommunicationTemplate) .FirstOrDefault(c => c.Id == communication.Id); var isApprovedCommunication = communication != null && communication.Status == Model.CommunicationStatus.Approved; var isReadyToSend = communication != null && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0); if (!isApprovedCommunication || !isReadyToSend) { return; } // If there are no pending recipients than just exit the method var communicationRecipientService = new CommunicationRecipientService(communicationRockContext); var hasUnprocessedRecipients = communicationRecipientService .Queryable() .ByCommunicationId(communication.Id) .ByStatus(CommunicationRecipientStatus.Pending) .ByMediumEntityTypeId(mediumEntityTypeId) .Any(); if (!hasUnprocessedRecipients) { return; } var currentPerson = communication.CreatedByPersonAlias?.Person; var mergeFields = GetAllMergeFields(currentPerson, communication.AdditionalLavaFields); var globalAttributes = GlobalAttributesCache.Get(); var templateEmailMessage = GetTemplateRockEmailMessage(communication, mergeFields, globalAttributes); var organizationEmail = globalAttributes.GetValue("OrganizationEmail"); var publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false; var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(); // Loop through recipients and send the email var recipientFound = true; while (recipientFound) { using (var recipientRockContext = new RockContext()) { var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); // This means we are done, break the loop if (recipient == null) { recipientFound = false; break; } // Not valid save the obj with the status messages then go to the next one if (!ValidRecipient(recipient, communication.IsBulkCommunication)) { recipientRockContext.SaveChanges(); continue; } try { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); var recipientEmailMessage = GetRecipientRockEmailMessage(templateEmailMessage, communication, recipient, mergeObjects, organizationEmail, mediumAttributes); var result = SendEmail(recipientEmailMessage); // Update recipient status and status note recipient.Status = result.Status; recipient.StatusNote = result.StatusNote; recipient.TransportEntityTypeName = this.GetType().FullName; // Log it try { var historyChangeList = new History.HistoryChangeList(); historyChangeList.AddChange( History.HistoryVerb.Sent, History.HistoryChangeType.Record, $"Communication") .SetRelatedData(recipientEmailMessage.FromName, communicationEntityTypeId, communication.Id) .SetCaption(recipientEmailMessage.Subject); HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } catch (Exception ex) { ExceptionLogService.LogException(ex); recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => "); } recipientRockContext.SaveChanges(); } } } }