Email Utility for sending Custom WFFM email

Email Utility for sending Custom WFFM email

In my last blog we have created a custom save action for sending the email based on the drop list selection now we will extend our last blog by creating an email utility for sending the email with all the WFFM form fields and the selected email item.

In our last blog we were calling

EmailUtility.SendCustomEmail(this, emailItem, adaptedFields);

In this blog we are creating the definition for this function.

We have created a class EmailUtility and that class has definition of above fuction.

using System;

using System.Net;

using System.Net.Mail;

using System.Text;

using System.Xml;

using Sitecore.Data.Items;

using Sitecore.StringExtensions;

using Sitecore.WFFM.Abstractions.Actions;

using Sitecore.WFFM.Actions.Base;

 

namespace NameSpace

{

public static class EmailUtility

{

public static void SendCustomEmail(WffmSaveAction saveAction, Item emailItem, AdaptedResultList adaptedFields)

{

//get the smtp host, username, password etc. from custom save action’s parameter

Item customSaveActionItem = Sitecore.Context.Database.GetItem(saveAction.ActionID);

 

string smtpHost = string.Empty;

string smtpPort = string.Empty;

string smtpUsername = string.Empty;

string smtpPassword = string.Empty;

bool IsBodyHtml = false;

bool enableSSL = false;

 

if (customSaveActionItem != null)

{

//parameters is a non-structured XML.  Add xml tags so that it becomes a xml string that can be loaded in the xmldocument object.

string xmlString = “<xml>” + customSaveActionItem.Fields[“Parameters”].Value + “</xml>”;

XmlDocument xdoc = new XmlDocument();

xdoc.LoadXml(xmlString);

 

XmlNodeList node = xdoc.GetElementsByTagName(“Host”);

if (node.Count > 0)

{

smtpHost = node[0].InnerText;

}

 

node = xdoc.GetElementsByTagName(“IsBodyHtml”);

if (node.Count > 0)

{

IsBodyHtml = (node[0].InnerText.ToLower() == “true”);

}

 

node = xdoc.GetElementsByTagName(“Login”);

if (node.Count > 0)

{

smtpUsername = node[0].InnerText;

}

 

 

node = xdoc.GetElementsByTagName(“Password”);

if (node.Count > 0)

{

smtpPassword = node[0].InnerText;

}

 

node = xdoc.GetElementsByTagName(“Port”);

if (node.Count > 0)

{

smtpPort = node[0].InnerText;

}

 

node = xdoc.GetElementsByTagName(“enableSsl”);

if (node.Count > 0)

{

enableSSL = (node[0].InnerText.ToLower() == “true”);

}

 

}

 

#region mail body

 

StringBuilder mailBody = new StringBuilder();

foreach (AdaptedControlResult adaptedControlResult in adaptedFields)

{

//one of the field in this list is the “DRIVER FIELD”.

//it’s value will be equal to GUID.  We do not want to GUID to go out in the email.

//we should replace it with a friendly version instead.

string captchaField = null;

if (!adaptedControlResult.FieldID.IsNullOrEmpty())

{

var wffmField = Sitecore.Context.Database.GetItem(adaptedControlResult.FieldID);

if (wffmField != null && wffmField.Fields[“Field Link”] != null)

{

captchaField = wffmField.Fields[“Field Link”].Value;

}

}

//Ignoring the captch field fom email body

if (captchaField == “{7FB270BE-FEFC-49C3-8CB4-947878C099E5}”) continue;

if (IsBodyHtml) mailBody.Append(“<b>”);

mailBody.Append(adaptedControlResult.FieldName);

if (IsBodyHtml) mailBody.Append(“</b>”);

 

mailBody.Append(“:”);

mailBody.Append(adaptedControlResult.Value);

 

mailBody.Append(NewLine(IsBodyHtml));

}

 

 

if (IsBodyHtml) mailBody.Append(“<b>”);

mailBody.Append(“Metadata: “);

if (IsBodyHtml) mailBody.Append(“</b>”);

mailBody.Append(NewLine(IsBodyHtml));

 

 

//add current page to mail

if (IsBodyHtml) mailBody.Append(“<b>”);

mailBody.Append(“Current Page: “);

if (IsBodyHtml) mailBody.Append(“</b>”);

mailBody.Append(NewLine(IsBodyHtml));

 

 

#endregion

 

 

 

SmtpClient smtpClient = new SmtpClient();

smtpClient.EnableSsl = enableSSL;

smtpClient.Host = smtpHost;

smtpClient.Port = string.IsNullOrEmpty(smtpPort) ? 25 : Convert.ToInt32(smtpPort);

 

 

if (!string.IsNullOrEmpty(smtpUsername) && !string.IsNullOrEmpty(smtpPassword))

{

NetworkCredential networkCredential = new NetworkCredential(smtpUsername, smtpPassword);

smtpClient.UseDefaultCredentials = false;

smtpClient.Credentials = (ICredentialsByHost)networkCredential;

}

 

MailMessage message = new MailMessage();

 

string[] toAddress = emailItem.Fields[“To_Mails_IDs”].Value.Split(new char[] { ‘,’, ‘;’ });

foreach (string address in toAddress)

{

if (!string.IsNullOrEmpty(address)) message.To.Add(new MailAddress(address));

}

 

string[] ccAddress = emailItem.Fields[“CC_Mails_IDs”].Value.Split(new char[] { ‘,’, ‘;’ });

foreach (string address in ccAddress)

{

if (!string.IsNullOrEmpty(address)) message.CC.Add(new MailAddress(address));

}

 

string[] bccAddress = emailItem.Fields[“BCC_Mails_IDs”].Value.Split(new char[] { ‘,’, ‘;’ });

foreach (string address in bccAddress)

{

if (!string.IsNullOrEmpty(address)) message.Bcc.Add(new MailAddress(address));

}

 

message.From = string.IsNullOrEmpty(emailItem.Fields[“From_Mail_ID”].Value) ? new MailAddress(“example@chs.org”) : new MailAddress(emailItem.Fields[“From_Mail_ID”].Value);

 

 

message.Subject = !string.IsNullOrEmpty(emailItem.Fields[“Mail_Subject”].Value) ? emailItem.Fields[“Mail_Subject”].Value : “Some default value”;

message.Body = mailBody.ToString();

message.IsBodyHtml = IsBodyHtml;

message.BodyEncoding = Encoding.UTF8;

message.SubjectEncoding = Encoding.UTF8;

 

smtpClient.Send(message);

}

 

private static string NewLine(bool isbodyHtml)

{

if (isbodyHtml) return “</br>”;

else return Environment.NewLine;

 

}

}

}

Advertisements
WFFM Custom Save Action Send Email based on Dropdown Selection.

WFFM Custom Save Action Send Email based on Dropdown Selection.

WFFM have its own send email action but we can’t change the email field during run time. Suppose we have a category dropdown and based on category WFFM need to send email to different group. So if category is “Marketing” is selected then email should go to the marketing group and if category “HR” is selected then email should go to the human resource group.

To resolve this kind of problem we have created a custom droplist field which is just copy of existing droplist field. Motive behind creating this duplicate field is just to differentiate default dropdown field for our custom save action. Datasource for this field should be a template which have all required email field such as TO, CC, BCC, Subject etc.

We have created a custom save action for sending email based on selection by navigating sitecore/System/Modules/Web Forms for Marketers/Settings/Actions/Save Actions

You need to right click on the save actions item and select save action button from insert option, it will open the dialog and you need to enter the name of the action.

In the new save action we need to fill the Assembly and Class fields by entering the name of the assembly and class name.

We will also use the parameter field for SMTP information for sending custom email by using this SMTP information.

We are inheriting the Sitecore.WFFM.Actions.Base.WffmSaveAction abstract class and overriding the Execute method.

using System;

using Castle.Core.Internal;

using Glass.Mapper.Sc;

using Sitecore;

using Sitecore.Data;

using Sitecore.WFFM.Abstractions.Actions;

using Sitecore.WFFM.Actions.Base;

using Log = Sitecore.Diagnostics.Log;

 

namespace Namespace.FormActions

{

public class CustomSendEmail : WffmSaveAction

{

public override void Execute(ID formId, AdaptedResultList adaptedFields,

ActionCallContext actionCallContext = null, params object[] data)

{

var sitecoreService = new SitecoreService(Context.Database);

var adaptedDriverField = FindCustomEmailDropListField(adaptedFields);

if (adaptedDriverField == null)

{

// Log the warning if this save action is applied without using custom field

Log.Warn(

“Warning: Custom Send Email Custom action will not work without Custom Email Drop List field, please make sure you have this type of field (Field Type ID =add the field id for ease) in WFFM Form: ” +

formId, this);

return;

}

try

{

if (!adaptedDriverField.Value.IsNullOrEmpty())

{

//Get the ID for the selected item

var adaptedFieldValue = ID.Parse(adaptedDriverField.Value);

if (!adaptedFieldValue.IsGlobalNullId)

{

// Get the Item from sitecore based on selected ID

var emailItem = Context.Database.GetItem(adaptedFieldValue);

if (emailItem != null)

{

// emailItem will have field for email action such as to, cc, bcc, subject etc. this method will use these field as well as the smtp information on the action to send the email

EmailUtility.SendCustomEmail(this, emailItem, adaptedFields);

}

}

}

}

catch (Exception ex)

{

Log.Error(“Error: Custom Send Email Custom action is not working for WFFM Form: ” + formId, ex, this);

}

}

 

private AdaptedControlResult FindCustomEmailDropListField(AdaptedResultList adaptedFields)

{

AdaptedControlResult driverField = null;

foreach (AdaptedControlResult adpatedControlResult in adaptedFields)

{

var fieldItem = Context.Database.GetItem(adpatedControlResult.FieldID);

// get the custom duplicate dropdown field

if (fieldItem.Fields[“Field Link”].Value != “ID of the Field”) continue;

driverField = adpatedControlResult;

break;

}

return driverField;

}

}

}

Sitecore WFFM Ajax MVC call is duplicating the content

Sitecore WFFM Ajax MVC call is duplicating the content

For one of our Sitecore 8.1 rev 151217 based project we had a requirement of AJAX call in WFFM form. We were creating a form and marking “Is Ajax MVC Form” as checked and doing appropriate change for using MVC Form rendering to fire a AJAX call.

The forms are rendering and visible on the page, but when we were trying to submit the form its injecting full page again including thank you message instead of only showing thank you message. Therefore, it was showing duplicate content on page.

First I was thinking this error may due to some missing configuration or something else because the project I am working on is not a new one and its was previously upgraded to Sitecore 8.1 rev 151217 but to make sure, I installed a vanilla instance with WFFM only and add the sample forms coming with WFFM module on single page with MVC form rendering but I was facing same problem here as well. For using MVC form rendering I was using the WFFM installation guide as reference by Sitecore. However, it was not reproducible on Sitecore 8.1 rev. 160519 (8.1 Update-3) + WFFM 8.1 rev. 160523 (Update-3) and higher. So defiantly it was a problem in Sitecore 8.1 151217.

Now there were two solutions to resolve this problem –

  1. Upgrade our current solution to the higher version of Sitecore.
  2. Update or apply some patch in current version so it resolves the problem.

With First solution it was not possible to upgrade the current version because it was not in my territory. So I have decided to resolve this problem by apply some patch or code update. Meanwhile I also log a support ticket to the Sitecore. At the end I got following two solutions one was by me and second was provide by Sitecore support.

Solution1 – update the wffm.js file for the response

When we hit the submit button of mvc ajax wffm form it calls form.submit method written in \sitecore modules\Web\Web Forms for Marketers\mvc\wffm.js file. This method fire a ajax call to the server and get the result based on the sumittion success or fail. We can filter the result for success return of the ajax in the js file so it will clean the duplicate file

success: function (res) {self.formSubmitSuccess(form, res);}

All we need to perform functions on res (data) in above js code.

Solution 2 – This solution was provided by Sitecore where we need to update the FormViewModel.cshtml file with below code. You can open following file in any editor and can paste the below code.

-Website\Views\Form\EditorTemplates\FormViewModel.cshtml

@using Sitecore.Forms.Mvc

@using Sitecore.Forms.Mvc.Html

@using Sitecore.Globalization

@model Sitecore.Forms.Mvc.ViewModels.FormViewModel

@{

var attributes = new RouteValueDictionary()

{

{ “enctype”, “multipart/form-data” },

{ “class”, @Model.CssClass },

{ “id”, Model.ClientId },

{ “role”, “form” },

{ Constants.Wffm, Model.Item.ID }

};

var queryString = new RouteValueDictionary(Request.QueryString.AllKeys.ToDictionary(key => key, key => (object)Request.QueryString[key]));

if (Model.IsAjaxForm)

{

attributes.Add(“data-wffm-ajax”, true);

if (!string.IsNullOrEmpty(Model.RedirectUrl))

{

attributes.Add(“data-wffm-redirect”,  UrlHelper.GenerateContentUrl(Model.RedirectUrl, Context));

}

if (!IsPost)

{

queryString.Add(“wffm.” + Constants.FormItemId, Model.Item.ID.ToGuid());

queryString.Add(“wffm.” + Constants.Id, Model.UniqueId);

}

Html.BeginRouteForm(“Form”, queryString, FormMethod.Post, attributes);

}

else

{

Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, queryString, FormMethod.Post, attributes);

}

var uniqueId = Model.UniqueId.ToString();

Html.EnableClientValidation(true);

Html.EnableUnobtrusiveJavaScript(true);

@Html.AntiForgeryToken()

@Html.Hidden(Constants.Id, uniqueId)

@Html.Hidden(Constants.FormItemId, Model.Item.ID)

if (Model.ShowTitle)

{

var headerText = Html.BootstrapText(“Title”);

@Html.BootstrapHeader(headerText.ToString(), Model.TitleTag)

}

if (Model.SuccessSubmit)

{

@Html.Encode(!string.IsNullOrEmpty(Model.SuccessMessage) ? Model.SuccessMessage : Translate.Text(“Default success message.”))

return;

}

if (Model.Errors.Any())

{

@Html.BootstrapWarningsList(Model.Errors)

}

if (Model.ShowInformation)

{

@Html.BootstrapText(“Information”)

}

@Html.BootstrapValidationSammary(false)

@Html.EditorFor(x => Model.Sections)

if (Model.ShowFooter)

{

@Html.BootstrapText(“Footer”)

}

@Html.BootstrapSubmit()

Html.EndForm();

}

And that’s it. Thank you!

Sitecore WFFM error for multilingual form

Sitecore WFFM error for multilingual form

For one of our Multilanguage multisite project there was need to create WFFM form in multiple languages such and French, Hungarian, Russian etc. but when content editor wants to create a new language version of WFFM form he was getting server error says “parameter xml is null or empty” see below section-

wffm_parameter_xml_error.png

 

 

Server Error in ‘/’ Application.

Parameter xml is null or empty

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Parameter xml is null or empty

[InvalidOperationException: Parameter xml is null or empty]

Sitecore.Form.Core.ContentEditor.Data.ListDefinition.Parse(String xml) +233

Sitecore.Form.UI.Controls.GroupListBuilder.BuildGrid(Control parent) +469

System.Web.UI.Control.LoadRecursive() +71

System.Web.UI.Control.LoadRecursive() +190

System.Web.UI.Control.AddedControl(Control control, Int32 index) +257

Sitecore.Web.UI.Sheer.ClientPage.AddControl(Control parent, Control control, String placeholder) +291

Sitecore.Shell.Applications.ContentEditor.EditorFormatter.AddEditorControl(Control parent, Control editor, Field field, Boolean hasRibbon, Boolean readOnly, String value) +367

Sitecore.Shell.Applications.ContentEditor.EditorFormatter.RenderField(Control parent, Field field, Item fieldType, Boolean readOnly, String value) +1495

 

 

This error was only for some languages not for all, after doing some investigation on this issue I found that the languages where this error was occurring didn’t have these language versions in standard value off WFFM form. I try to create language version of these languages on standard value but here I was getting the same error.

Reason of this error –

reason of this error is save action field was not shared in our project due to some other customization in WFFM. WFFM by default doesn’t work in this ways with unshared save action field.

Solution –

  1. Mark the save action field as shared if it is not marked as shared accidently this will resolve the problem
  2. But is case where intensely save action field is unmarked shared field we need to create language version of standard value of WFFM form item.

We have two options to perform this action –

  1. make save action as shared for few time create language version for different required language and then unmark it again. It done.
  2. If there is strict restriction for make save action shared field then, administrator need to change the view mode in raw value (short cut – ctrl+alt+shift+r) from view ribbon menu. Create language version off standard value of WFFM form item (there will be no any error in raw value view mode) and copy the default content of save action field from English or default language version of item and paste it in the newly created language versions’ s save action field. Preform these steps for all the language where this error is occurring. Change the view again in standard mode.

That’s it thanks and cheers!!