/// <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> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { using ( var rockContext = new RockContext() ) { // Requery the Communication object communication = new CommunicationService( rockContext ) .Queryable( "CreatedByPersonAlias.Person" ) .FirstOrDefault( c => c.Id == 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 ) ) { var currentPerson = communication.CreatedByPersonAlias.Person; var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); var globalConfigValues = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields( currentPerson ); // From - if none is set, use the one in the Organization's GlobalAttributes. string fromAddress = communication.GetMediumDataValue( "FromAddress" ); if ( string.IsNullOrWhiteSpace( fromAddress ) ) { fromAddress = globalAttributes.GetValue( "OrganizationEmail" ); } string fromName = communication.GetMediumDataValue( "FromName" ); if ( string.IsNullOrWhiteSpace( fromName ) ) { fromName = globalAttributes.GetValue( "OrganizationName" ); } // Resolve any possible merge fields in the from address fromAddress = fromAddress.ResolveMergeFields( globalConfigValues, currentPerson ); fromName = fromName.ResolveMergeFields( globalConfigValues, currentPerson ); MailMessage message = new MailMessage(); message.From = new MailAddress( fromAddress, fromName ); // Reply To string replyTo = communication.GetMediumDataValue( "ReplyTo" ); if ( !string.IsNullOrWhiteSpace( replyTo ) ) { message.ReplyToList.Add( new MailAddress( replyTo ) ); } CheckSafeSender( message, globalAttributes ); // CC string cc = communication.GetMediumDataValue( "CC" ); if ( !string.IsNullOrWhiteSpace( cc ) ) { foreach ( string ccRecipient in cc.SplitDelimitedValues() ) { message.CC.Add( new MailAddress( ccRecipient ) ); } } // BCC string bcc = communication.GetMediumDataValue( "BCC" ); if ( !string.IsNullOrWhiteSpace( bcc ) ) { foreach ( string bccRecipient in bcc.SplitDelimitedValues() ) { message.Bcc.Add( new MailAddress( bccRecipient ) ); } } message.IsBodyHtml = true; message.Priority = MailPriority.Normal; using ( var smtpClient = GetSmtpClient() ) { // Add Attachments string attachmentIds = communication.GetMediumDataValue( "Attachments" ); if ( !string.IsNullOrWhiteSpace( attachmentIds ) ) { 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 ) { message.Attachments.Add( new Attachment( binaryFile.ContentStream, binaryFile.FileName ) ); } } } } var historyService = new HistoryService( rockContext ); var recipientService = new CommunicationRecipientService( rockContext ); var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; var communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; var communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; bool recipientFound = true; while ( recipientFound ) { var recipient = Rock.Model.Communication.GetNextPending( communication.Id, rockContext ); if ( recipient != null ) { if ( string.IsNullOrWhiteSpace( recipient.PersonAlias.Person.Email ) ) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No Email Address"; } else { try { message.To.Clear(); message.Headers.Clear(); message.AlternateViews.Clear(); message.To.Add( new MailAddress( recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName ) ); // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( globalConfigValues ); // Subject message.Subject = communication.Subject.ResolveMergeFields( mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny (for example "Hey “double-quotes†from ‘single quote’") message.Subject = message.Subject.ReplaceWordChars(); // Add any additional headers that specific SMTP provider needs AddAdditionalHeaders( message, recipient ); // Add text view first as last view is usually treated as the preferred view by email readers (gmail) string plainTextBody = Rock.Communication.Medium.Email.ProcessTextBody( communication, globalAttributes, mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny plainTextBody = plainTextBody.ReplaceWordChars(); if ( !string.IsNullOrWhiteSpace( plainTextBody ) ) { AlternateView plainTextView = AlternateView.CreateAlternateViewFromString( plainTextBody, new System.Net.Mime.ContentType( MediaTypeNames.Text.Plain ) ); message.AlternateViews.Add( plainTextView ); } // Add Html view string htmlBody = Rock.Communication.Medium.Email.ProcessHtmlBody( communication, globalAttributes, mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny htmlBody = htmlBody.ReplaceWordChars(); if ( !string.IsNullOrWhiteSpace( htmlBody ) ) { AlternateView htmlView = AlternateView.CreateAlternateViewFromString( htmlBody, new System.Net.Mime.ContentType( MediaTypeNames.Text.Html ) ); message.AlternateViews.Add( htmlView ); } smtpClient.Send( message ); recipient.Status = CommunicationRecipientStatus.Delivered; string statusNote = StatusNote; if ( !string.IsNullOrWhiteSpace( statusNote ) ) { recipient.StatusNote = statusNote; } recipient.TransportEntityTypeName = this.GetType().FullName; historyService.Add( new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = string.Format( "Sent communication from <span class='field-value'>{0}</span>.", message.From.DisplayName ), Caption = message.Subject, RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id } ); } catch ( Exception ex ) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Message; } } rockContext.SaveChanges(); } else { recipientFound = false; } } } } } }
/// <summary> /// Executes this instance. /// </summary> public void Execute() { using ( var rockContext = new RockContext() ) { var communication = new CommunicationService( rockContext ).Get( CommunicationId ); if ( communication != null && communication.Status == CommunicationStatus.PendingApproval ) { // get notification group var approvers = new GroupService( rockContext ).Get(SystemGuid.Group.GROUP_COMMUNICATION_APPROVERS.AsGuid()); if ( approvers != null ) { var mergeFields = new Dictionary<string, object>(); var globalAttributeFields = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields( null ); globalAttributeFields.ToList().ForEach( d => mergeFields.Add( d.Key, d.Value ) ); string fromName = Rock.Web.Cache.GlobalAttributesCache.Value("OrganizationName"); string fromEmail = Rock.Web.Cache.GlobalAttributesCache.Value( "OrganizationEmail" ); string subject = "Pending Communication Requires Approval"; var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read( rockContext ).GetValue( "ExternalApplicationRoot" ); string communicationDetails = string.Empty; string typeName = string.Empty; // get custom details by type switch ( communication.Medium.TypeName ) { case "Rock.Communication.Medium.Email": string emailFromName = communication.GetMediumDataValue( "FromName" ); string emailFromAddress = communication.GetMediumDataValue( "FromAddress" ); communicationDetails = string.Format( @" <strong>From Name:</strong> {0}<br/> <strong>From Address:</strong> {1}<br/> <strong>Subject:</strong> {2}<br/>" , emailFromName , emailFromAddress , communication.Subject ); typeName = "Email"; break; case "Rock.Communication.Medium.Sms": int fromValueId = communication.GetMediumDataValue( "FromValue" ).AsInteger(); var fromValue = new DefinedValueService( rockContext ).Get( fromValueId ); typeName = "SMS"; if ( fromValue != null ) { communicationDetails = string.Format( "<strong>SMS Number:</strong> {0} ({1})<br/>", fromValue.Description, fromValue.Value ); } break; } // create approval link if one was not provided if ( ApprovalPageUrl == null ) { ApprovalPageUrl = string.Format( "{0}Communication/{1}", Rock.Web.Cache.GlobalAttributesCache.Read( rockContext ).GetValue( "InternalApplicationRoot" ), communication.Id ); } foreach ( var approver in approvers.Members ) { string message = string.Format( @" {{{{ 'Global' | Attribute:'EmailHeader' }}}} <p>{0}:</p> <p>A new communication requires approval. Information about this communication can be found below.</p> <p> <strong>From:</strong> {1}<br /> <strong>Type:</strong> {2}<br /> {3} <strong>Recipient Count:</strong> {4}<br /> </p> <p> <a href='{5}'>View Communication</a> </p> {{{{ 'Global' | Attribute:'EmailFooter' }}}}", approver.Person.NickName, communication.SenderPersonAlias.Person.FullName, typeName, communicationDetails, communication.Recipients.Count(), ApprovalPageUrl); var recipients = new List<string>(); recipients.Add( approver.Person.Email ); Email.Send( fromEmail, fromName, subject, recipients, message.ResolveMergeFields( mergeFields ), appRoot, string.Empty, null, false ); } } } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { using ( var rockContext = new RockContext() ) { // Requery the Communication communication = new CommunicationService( rockContext ).Get( communication.Id ); if ( communication != null && communication.Status == CommunicationStatus.Approved && communication.Recipients.Any(r => r.Status == CommunicationRecipientStatus.Pending) && ( !communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo( RockDateTime.Now ) <= 0 ) ) { // Remove all non alpha numeric from fromValue string fromValue = communication.GetMediumDataValue( "NoReply_FromValue" ); //Ensure that the fromValue is correct fromValue = new string( fromValue.ToCharArray().Where( c => char.IsLetterOrDigit( c ) || char.IsWhiteSpace( c ) ).Take( 11 ).ToArray() ) ; string senderGuid = communication.GetMediumDataValue( "SenderGuid" ); if ( !string.IsNullOrWhiteSpace( fromValue ) && !string.IsNullOrWhiteSpace( senderGuid ) ) { string accountSid = GetAttributeValue( "SID" ); string authToken = GetAttributeValue( "Token" ); if (string.IsNullOrWhiteSpace(accountSid) || string.IsNullOrWhiteSpace(authToken)) { throw new Exception("Either SID or Token not provided"); } var twilio = new TwilioRestClient( accountSid, authToken ); var historyService = new HistoryService( rockContext ); int personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; int communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; int communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; var sender = new PersonService( rockContext ).Get( senderGuid.AsGuid() ); var mergeFields = GlobalAttributesCache.GetMergeFields( null ); if ( sender != null ) { mergeFields.Add( "Sender", sender ); } bool recipientFound = true; while ( recipientFound ) { var recipient = Rock.Model.Communication.GetNextPending( communication.Id, rockContext ); if ( recipient != null ) { try { var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers .FirstOrDefault(p => p.IsMessagingEnabled); if ( phoneNumber != null ) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( mergeFields ); string message = communication.GetMediumDataValue( "NoReply_Message" ); string footer = GetAttributeValue( "footer" ); if ( communication.GetMediumDataValue( "NoReply_AppendUserInfo" ).AsBoolean() && !string.IsNullOrEmpty( footer ) ) { message += "\n " + footer; } else { message += "\n This message was sent on behalf of {{ GlobalAttribute.OrganizationName }} from a no reply number."; } message = message.ReplaceWordChars(); message = message.ResolveMergeFields( mergeObjects ); string twilioNumber = phoneNumber.Number; if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) ) { twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number; } var globalAttributes = GlobalAttributesCache.Read(); if (globalAttributes == null) { throw new Exception("Error getting Global Attributes"); } string callbackUrl = globalAttributes.GetValue( "PublicApplicationRoot" ) + "Webhooks/Twilio.ashx"; var response = twilio.SendMessage( fromValue, twilioNumber, message, callbackUrl ); if (response != null) { recipient.Status = GetCommunicationRecipientStatus(response); recipient.TransportEntityTypeName = GetType().FullName; recipient.UniqueMessageId = response.Sid; try { historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = "Sent an alphanumeric SMS message from " + fromValue + ".", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } else { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No response from Twilio"; } } 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; ExceptionLogService.LogException( ex, null ); } rockContext.SaveChanges(); } else { recipientFound = false; } } } } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { var rockContext = new RockContext(); // Requery the Communication communication = new CommunicationService( rockContext ).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 ) ) { string fromPhone = string.Empty; string fromValue = communication.GetMediumDataValue( "FromValue" ); int fromValueId = int.MinValue; if ( int.TryParse( fromValue, out fromValueId ) ) { fromPhone = DefinedValueCache.Read( fromValueId, rockContext ).Value; } if ( !string.IsNullOrWhiteSpace( fromPhone ) ) { string accountSid = GetAttributeValue( "SID" ); string authToken = GetAttributeValue( "Token" ); var twilio = new TwilioRestClient( accountSid, authToken ); var historyService = new HistoryService( rockContext ); var recipientService = new CommunicationRecipientService( rockContext ); var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; var communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; var communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; var globalConfigValues = GlobalAttributesCache.GetMergeFields( null ); bool recipientFound = true; while ( recipientFound ) { var recipient = recipientService.Get( communication.Id, CommunicationRecipientStatus.Pending ).FirstOrDefault(); if ( recipient != null ) { try { var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers .Where( p => p.IsMessagingEnabled ) .FirstOrDefault(); if ( phoneNumber != null ) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( globalConfigValues ); string message = communication.GetMediumDataValue( "Message" ); message = message.ResolveMergeFields( mergeObjects ); string twilioNumber = phoneNumber.Number; if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) ) { twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number; } var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); string callbackUrl = globalAttributes.GetValue( "PublicApplicationRoot" ) + "Webhooks/Twilio.ashx"; var response = twilio.SendMessage( fromPhone, twilioNumber, message, callbackUrl ); recipient.Status = CommunicationRecipientStatus.Delivered; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.Sid; try { historyService.Add( new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = "Sent 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(); } else { recipientFound = false; } } } } }
/// <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 mergeValues = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields( null ); // Requery the Communication object communication = new CommunicationService( rockContext ).Get( communication.Id ); mergeValues.Add( "Communication", communication ); 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 ); } } } } // Body string htmlContent = communication.GetMediumDataValue( "HtmlMessage" ); sbContent.Append( Email.ProcessHtmlBody( communication, globalAttributes, mergeValues ) ); // 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(); }