Send Email fields not rendering in Sitecore Web Forms For Marketers - forms

I have an issue with the WFFM Send Email Message save action (Sitecore 6.5.0). I'm trying to send an email that includes the form placeholders from the "Insert Field" dropdown in the Send Email editor. Sometimes the fields will render correctly, but most times the email will include the placeholder text instead of the field's actual value.
For example, this is the email that is coming through:
First Name: [First Name]
Last Name: [Last Name]
Email: [Email Address]
Company Name: [Company Name]
Phone Number: [Phone Number]
I think it has to do with the Send Email editor using a rich text editor for the email template, but I've tried adjusting the message's HTML to no avail. This is what the markup looks like: (the <p> tags and labels used to be inline, but that didn't work either)
<p>First Name:
[<label id="{F49F9E49-626F-44DC-8921-023EE6D7948E}">First Name</label>]
</p>
<p>Last Name:
[<label id="{9CE3D48C-59A0-432F-B6F1-3AFD03687C94}">Last Name</label>]
</p>
<p>Email:
[<label id="{E382A37E-9DF5-4AFE-8780-17169E687805}">Email Address</label>]
</p>
<p>Company Name:
[<label id="{9C08AC2A-4128-47F8-A998-12309B381CCD}">Company Name</label>]
</p>
<p>Phone Number:
[<label id="{4B0C5FAC-A08A-4EF2-AD3E-2B7FDF25AFA7}">Phone Number</label>]
</p>
Does anyone know what could be going wrong?

I have encountered this issue before, but was using a custom email action. I managed to fix it by not using the deprecated methods in the SendMail class and instead using the
Sitecore.Form.Core.Pipelines.ProcessMessage namespace's ProcessMessage and ProcessMessageArgs classes.
My use case was a little more complicated than yours, as we were also attaching a PDF brochure to our message (which is why we were using the custom email action in the first place), but here is the code:
public class SendBrochureEmail : SendMail, ISaveAction, ISubmit
{
public new void Execute(ID formId, AdaptedResultList fields, params object[] data)
{
try
{
var formData = new NameValueCollection();
foreach (AdaptedControlResult acr in fields)
{
formData[acr.FieldName] = acr.Value;
}
var senderName = formData["Your Name"];
var emailTo = formData["Recipient Email"];
var recipientName = formData["Recipient Name"];
var documentTitle = formData["Document Title"];
if (documentTitle.IsNullOrEmpty())
{
documentTitle = String.Format("Documents_{0}", DateTime.Now.ToString("MMddyyyy"));
}
Subject = documentTitle;
if (!String.IsNullOrEmpty(emailTo))
{
BaseSession.FromName = senderName;
BaseSession.CatalogTitle = documentTitle;
BaseSession.ToName = recipientName;
var tempUploadPath = Sitecore.Configuration.Settings.GetSetting("TempPdfUploadPath");
var strPdfFilePath =
HttpContext.Current.Server.MapPath(tempUploadPath + Guid.NewGuid().ToString() + ".pdf");
//initialize object to hold WFFM mail/message arguments
var msgArgs = new ProcessMessageArgs(formId, fields, MessageType.Email);
var theDoc = PdfDocumentGenerator.BuildPdfDoc();
theDoc.Save(strPdfFilePath);
theDoc.Clear();
FileInfo fi = null;
FileStream stream = null;
if (File.Exists(strPdfFilePath))
{
fi = new FileInfo(strPdfFilePath);
stream = fi.OpenRead();
//attach the file with the name specified by the user
msgArgs.Attachments.Add(new Attachment(stream, documentTitle + ".pdf", "application/pdf"));
}
//get the email's "from" address setting
var fromEmail = String.Empty;
var fromEmailNode = Sitecore.Configuration.Factory.GetConfigNode(".//sc.variable[#name='fromEmail']");
if (fromEmailNode != null && fromEmailNode.Attributes != null)
{
fromEmail = fromEmailNode.Attributes["value"].Value;
}
//the body of the email, as configured in the "Edit" pane for the Save Action, in Sitecore
msgArgs.Mail.Append(base.Mail);
//The from address, with the sender's name (specified by the user) in the meta
msgArgs.From = senderName + "<" + fromEmail + ">";
msgArgs.Recipient = recipientName;
msgArgs.To.Append(emailTo);
msgArgs.Subject.Append(Subject);
msgArgs.Host = Sitecore.Configuration.Settings.MailServer;
msgArgs.Port = Sitecore.Configuration.Settings.MailServerPort;
msgArgs.IsBodyHtml = true;
//initialize the message using WFFM's built-in methods
var msg = new ProcessMessage();
msg.AddAttachments(msgArgs);
msg.BuildToFromRecipient(msgArgs);
//change links to be absolute instead of relative
msg.ExpandLinks(msgArgs);
msg.AddHostToItemLink(msgArgs);
msg.AddHostToMediaItem(msgArgs);
//replace the field tokens in the email body with the user-specified values
msg.ExpandTokens(msgArgs);
msg.SendEmail(msgArgs);
//no longer need the file or the stream - safe to close stream and delete delete it
if (fi != null && stream != null)
{
stream.Close();
fi.Delete();
}
}
else
{
Log.Error("Email To is empty", this);
throw new Exception("Email To is empty");
}
}
catch (Exception ex)
{
Log.Error("Test Failed.", ex, (object) ex);
throw;
}
finally
{
BrochureItems.BrochureItemIds = null;
}
}
public void Submit(ID formid, AdaptedResultList fields)
{
Execute(formid, fields);
}
public void OnLoad(bool isPostback, RenderFormArgs args)
{
}
}
It is very possible that the Email Action that WFFM ships with is using the deprecated methods, which could be your problem. I do not have time to look into it, but you can decompile the DLL and look to see what their Email Action is doing. Regardless, the above code should work out of the box, save for updating the fields to those that you are using and removing the code for attaching the PDF, should you choose to not have attachments.
Good luck, and happy coding :)

If you change a field on the form in any way (caption, name, type, etc) the link will change and you need to re-insert the placeholder and move it up to its location in your expected email. This is also true if you duplicate a form. You'll have to reinsert all the fields in the email or you will just get the outcome you show above.
Reinserting upon a change will ensure the value is collected!

Related

MailKit HtmlBody Always Null

I"m trying to get the html from an email retrieved in Gmail. No issues getting the emails however when I attempt to get the HtmlBody it is always null. HTML is present according to the bodyparts.
using (var imap = new ImapClient())
{
imap.Connect("imap.gmail.com", 993);
imap.Authenticate(Login, PW);
var inbox = imap.Inbox;
inbox.Open(FolderAccess.ReadWrite);
string body = "";
if (html)
{
body = inbox.GetMessage(messageID).HtmlBody;
} else
{
body = inbox.GetMessage(messageID).TextBody;
}
imap.Disconnect(true);
return body;
}
I can see from the bodyparts that html is present and if I use this linq I'm able to get the encoded html.
var msg = inbox.GetMessage(messageID).BodyParts.OfType<MimePart>().First(x => x.ContentType.MimeType == "text/html");
Using this I can see there is a Text property but I'm not able to retrieve it. Can anyone assist in getting the unmodified html from Mailkit?
If you change your LINQ statement to:
var msg = inbox.GetMessage(messageID).BodyParts.OfType<TextPart>().First(x => x.ContentType.MimeType == "text/html");
... you'll be able to access the .Text property.
The other option is to cast the msg variable to a TextPart.
The reason you can't access the .Text property in your current code is that this property only exists on the TextPart subclass of MimePart (which is more abstract).

Google Apps Script_populate multiple templates depending on google form data and then email pdf copies

Help greatly needed.
Using Google Form to gather data, in order to populate one of 2 Google doc templates, dependent on whether option 1 or 2 is chosen in the Google form. Populated template to be saved in "final" folder as a PDF, and then emailed to the email address submitted in the Google form.
Currently, I'm able to generate the correct PDF files in the correct folder and send the email to the correct address, but there is no attachment and just the words [Object object].
Before I included the if/else function, I was able to correctly send the email with attachment, which means that I've caused a problem with the if/else and naming of the generated pdfs. I just can't figure it out.
function autoFillGoogleDocFromForm(e) {
//form values
var timestamp = e.values[0];
var firstName = e.values[1];
var lastName = e.values[2];
var email = e.values[3];
var multiplechoice = e.values[4];
if (multiplechoice == "Template 1") {
//This section will complete template 1
var file = DriveApp.getFileById("Template 1 ID");
//Create copy of Template 1
var folder = DriveApp.getFolderById("Templates folder ID")
var copy = file.makeCopy(lastName + ',' + firstName, folder);
//Open copy of Template 1 and replace key fields per form data
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{First Name}}', firstName);
body.replaceText('{{Last Name}}', lastName);
doc.saveAndClose();
Utilities.sleep(1500);
} else {
//This section will complete Template 2 by default
var file = DriveApp.getFileById("Template 2 ID");
//Create copy of Template 2
var folder = DriveApp.getFolderById("Templates folder ID")
var copy = file.makeCopy(lastName + ',' + firstName, folder);
//Open copy of Template 2 and replace key fields per form data
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{First Name}}', firstName);
body.replaceText('{{Last Name}}', lastName);
doc.saveAndClose();
Utilities.sleep(1500);
}
//create pdf copy of completed template either 1 or 2 depending on IF
var pdffolder = DriveApp.getFolderById("Templates folder ID");
var pdfFILE = DriveApp.getFileById(copy.getId()).getAs('application/pdf');
pdfFILE.setName(copy.getName() + ".pdf");
var theFolder = pdffolder;
var theFile = DriveApp.createFile(pdfFILE);
theFolder.addFile(theFile);
Utilities.sleep(1500);
var subject = "File attached";
var attach = theFile;
var pdfattach = attach.getAs(MimeType.PDF);
MailApp.sendEmail(email, subject, {attachments: [pdfattach]});
}
There are two signatures of MailApp that support attachments:
sendEmail(message)
and
sendEmail(recipient, subject, body, options)
There isn't a sendEmail(recipient, subject, options) method signature.
Include a body argument:
MailApp.sendEmail(email, subject, "☢☣☢",{attachments: [pdfattach]});

Google Form. Confirmation Email Script. With edit url

I have two working trigger functions in Google Script that fire when a form response spreadsheet gets a new submission. One inserts the "edit your submission" url into the spreadsheet. The other looks up the response's email and sends them a confirmation.
What I'm having a hard time understanding is how to populate the url first, and then send an email containing that url.
(Google Script is different to debug than js in the browser :\ )
Setup triggers
function Initialize() {
var triggers = ScriptApp.getScriptTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendConfirmationMail")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
assignEditUrls();
}
On form submit, searches for column titled "Clients Email", and sends a formatted email to them.
function SendConfirmationMail(e) {
try {
var ss, cc, sendername, subject, columns;
var message, value, textbody, sender;
var url;
// This is your email address and you will be in the CC
cc = Session.getActiveUser().getEmail();
// This will show up as the sender's name
sendername = "XXXX";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
subject = "Form Complete: Mobile App - Client Questionnaire";
// This is the body of the auto-reply
message = "Confirmation text here.<br><br>Thanks!<br><br>";
ss = SpreadsheetApp.getActiveSheet();
columns = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
// This is the submitter's email address
sender = e.namedValues["Clients Email"].toString();
// Only include form values that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] ) {
message += key + ' :: '+ e.namedValues[key] + "<br />";
}
}
textbody = message.replace("<br>", "\n\n");
GmailApp.sendEmail(sender, subject, textbody,
{cc: cc, name: sendername, htmlBody: message});
} catch (e) {
Logger.log(e.toString());
}
}
Separate function. Looks up form and applies the edit URL to the 26th column.
function assignEditUrls() {
var form = FormApp.openById('10BVYipGhDa_AthabHE-xxxxxx-hg');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses');
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = 26; // column number where URL's should be populated; A = 1, B = 2 etc
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}
Programmers are provided no direct control over the order that trigger functions will be invoked, when they are dependent on the same event.
In your situation though, there are a couple of options available.
Use only one trigger function for the event, and have it invoke the current functions in the order you require. (Alternatively, set assignEditUrls() up as the only trigger function, and have it call SendConfirmationMail() after completing its task.
Have SendConfirmationMail() check for the availability of the Edit URL, and call Utilities.sleep() if the URL isn't ready yet. (In a loop, until ready.)

How do I Show a SPList item Name in an Email sent by a timerJob?

I need to send an Email with a list items name of the rows my caml query picks out. I have this code:
SPQuery filter = new SPQuery();
filter.Query = string.Format("<Where><Leq><FieldRef Name=\"Revisionsdatum\" /><Value Type=\"DateTime\">{0}</Value></Leq></Where>", DateTime.Today.AddDays(14).ToString("yyyy-MM-ddThh:mm:ssZ"));
SPListItemCollection items = yourList.GetItems(filter);
foreach (var i in items)
{
string from = string.Empty;
string smtpAddress = string.Empty;
string to = "Someone#someCompany.com";
string subject = "Dudate is coming";
string body = "<h1>Hello!</h1><p>In to weeks an importent dudates comes({0}) with the name {2}.";//Here I would like to ad the dudate and the ListItems Name but how?
// get a reference to the current site collection's content database
SPWebApplication webApplication = this.Parent as SPWebApplication;
SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];
// get a reference to the "Tasks" list in the RootWeb of the first site collection in the content database
SPWeb rootWeb = contentDb.Sites[0].RootWeb;
SPList listjob = rootWeb.Lists.TryGetList("Tasks");
// Get sender address from web application settings
from = rootWeb.Site.WebApplication.OutboundMailSenderAddress;
// Get SMTP address from web application settings
smtpAddress = rootWeb.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
// Send an email if the news is approved
bool emailSent = SendMail(smtpAddress, subject, body, true, from, to, null, null);
}
I would bee greatfull for your answer!
You can get it as follows:
foreach (SPListItem item in items) \\ items is your SPListItemCollection
{
var fieldValue = item["Field Name"].ToString();
}
To convert DateTime object to CAML query use SPUtility.CreateISO8601DateTimeFromSystemDateTime() method.
Fields you need are referenced by i["Title"] and i["DueDate"].
Use StringBuilder object in foreach loop to construct the body of your mail and send the email after the loop. Your code will send one mail for each task.

How to Send automatic emails like newsletter

I see some question closed by administrator with similar question.
I will try to explain in detail the solution I'm looking for:
First I'm trying to develop a windows console application.
Sending frequency: monday to friday
How many users: from 5 to 20
Format of data:
A table where rows are countries and columns different types of products and the cells represent the sale of that country-product
Limitation:
Service users prefer not to use a pdf or excel or attachment of any type should be a html format possible to show in the body of mail
Currently I am creating the report almost artisan with something like:
.....
var myStringBuilder = new StringBuilder("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">");
myStringBuilder.Append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">");
myStringBuilder.Append("</head><body>");
myStringBuilder.AppendLine();
myStringBuilder.Append("<table style=\"font-family: Calibri; text-align: right; font-size: x-small;\">");
myStringBuilder.AppendLine();
var header = new StringBuilder("<tr><th>a</th><th>CATEG1</th><th>CATEG2</th><th>CATEG3</th><th>CATEG4</th><th>TOTAL</th></tr>");
var line = new StringBuilder("<tr><td>a</td><td>b</td><td>c</td><td>z</td><td>e</td><td>f</td></tr>");
foreach (var a in _actuals)
{
line.Replace("a", a.CountryName);
if(a.Segment.ToLowerInvariant().Equals("categ1")) {
line.Replace("b", "[" + string.Format("{0:0,#}", a.LsvLcFact / 1000) + "]"); }
else if (a.Segment.ToLowerInvariant().Equals("categ2")) {
line.Replace("c", "[" + string.Format("{0:0,#}", a.LsvLcFact / 1000) + "]"); }
else if (a.Segment.ToLowerInvariant().Equals("categ3")) {
line.Replace("z", "[" + string.Format("{0:0,#}", a.LsvLcFact / 1000) + "]"); }
else {
line.Replace("e", "[" + string.Format("{0:0,#}", a.LsvLcFact / 1000) + "]"); }
}
.....
And in the class to send mail something like:
public void SendResumen(string subject ,StringBuilder content)
{
var oMsg = new MailMessage...;
... add users
oMsg.Subject = subject;
var mimeType = new ContentType("text/html");
var alternate = AlternateView.CreateAlternateViewFromString(content.ToString(), mimeType);
oMsg.AlternateViews.Add(alternate);
oMsg.IsBodyHtml = true;
var cli = Client();
cli.Send(oMsg);
}
Finally, I hope you understand what I'm doing and the question is:
Is there a tool I can use to not generate as crafted the message body?
I have a VB application that can send out messages that have an HTML payload, and it doesn't use the AlternateView functionality.
Dim mail As New MailMessage(fromUser.Email, toUser.Email)
mail.Subject = subject
mail.IsBodyHtml = True
mail.Body = message
While it would be nice to use the AlternateView functionality for those email clients that can't read the HTML payload, your code can't really use it because you're only supplying an HTML message. If you did manage to get the AlternateView functionality to work here, any client that couldn't read HTML would see the HTML markup instead of just simple message text. For this to truly work, I think you would need to provide both a text and HTML email message body.
I Accept the suggest from #Jim-Mischel