Creating an HTML email within code
The PolicyCenter email subsystem sets
the email content type to HTML only if the HTML property on the email is set to true. The
following examples show how to work with HTML emails:
- The
EmailEnhancementexample is an email enhancement that sets the HTML property based on the template file extension. The enhancement also sets other useful header values that exist in an email object. - The
CreateEmailScreenexample shows how to modify the base configurationCreateEmailScreento add HTML template-related fields.
Note: If you are creating an email inline and you are sure that there is no possibility for an
attack in the HTML, you can set the email HTML property directly. However, if you do so,
ensure that you encode any user-supplied strings.
EmailEnhancement.gsx
The following code first populates a number of message headers, then provides a
useEmailTemplate method that example PCF screen
CreateEmailTemplate calls to set up the HTML email.
package gw.api.email
uses gw.api.util.DisplayableException
uses gw.document.TemplatePluginUtils
uses gw.plugin.email.IEmailTemplateDescriptor
uses java.io.StringReader
uses java.util.Map
uses java.util.HashSet
uses gw.api.util.LocaleUtil
uses gw.api.system.PLLoggerCategory
enhancement EmailEnhancement : gw.api.email.Email {
// list of headers, note the value should be ascii-7 or encoded
property get AUTOMATION_HEADER() : String { return "x-gw-Automation" }
property get EXPIRATION_HEADER() : String { return "Expiry-Date" }
property get REPLY_TO_ID_HEADER() : String { return "In-Reply-To" }
property get ID_HEADER() : String { return "Message-ID" }
property get REF_IDS_HEADER() : String { return "References" } // space delimited
property get RETURN_RECEIPT_ADDR_HEADER() : String { return "Return-Receipt-To" }
property get RETURN_READ_ADDR_HEADER() : String { return "Disposition-Notification-To" }
property get THREAD_HEADER() : String { return "Thread-Topic" }
property get THREAD_INDEX_HEADER() : String { return "Thread-Index" }
property get PRIORITY_HEADER() : String { return "Priority" }
property get PRIORITY_LOW() : String { return "5" }
property get PRIORITY_HIGH() : String { return "1" }
property get IMPORTANCE_HEADER() : String { return "Importance" }
property get IMPORTANCE_LOW() : String { return "low" }
property get IMPORTANCE_HIGH() : String { return "high" }
property get SENSITIVITY_HEADER() : String { return "Sensitivity" }
property get SENSITIVITY_CONFIDENTIAL() : String { return "Company-Confidential" }
property get SENSITIVITY_HIGH() : String { return "high" }
function useEmailTemplate(template : IEmailTemplateDescriptor, beans : Map<String,Object>) {
this.Html = template.Html
try {
var locale = template.Locale
if (locale == null) {
locale = LocaleUtil.getDefaultLocale()
}
TemplatePluginUtils.resolveTemplates( locale,
{new StringReader(template.Subject), new StringReader(template.Body)},
// setup the symbol table for the template processing, this is the same between email and note
\ iScriptHost -> {
// load the symbols supplied by the caller
var seen = new HashSet<String>()
for (entry in beans.entrySet()) {
var bean = entry.getValue()
iScriptHost.putSymbol(entry.Key, typeof(bean) as String, bean)
seen.add(entry.Key.toLowerCase())
}
// now load (or copy from other possible symbol names) the symbols that could be expected
// cc: claim, ...
// pc: policy, account, policyperiod, job, ...
if (not seen.contains( "activity" )) {
iScriptHost.putSymbol( "activity", Activity as String, null )
}
if (not seen.contains( "user" )) {
iScriptHost.putSymbol( "user", User as String, User.util.CurrentUser )
}
},
// process the result of the template expansion
\ results -> {
this.Subject = results[0]
this.Body = results[1]
} )
} catch (e : Throwable) {
PLLoggerCategory.MESSAGING_EMAIL.info("On ${template.getName()}", e)
throw new DisplayableException("On ${template.getName()} caught ", e);
}
}
}
CreateEmailScreen.pcf
The following example code adds additional functionality to the base configuration PolicyCenter
CreateEmailScreen PCF. This example version of the PCF screen adds HTML
template-related fields to the screen, include a read-only view of the HTML template. This
field (a TextAreaInput widget) contains a PostOnChange
action that calls method executeTemplate, which, in turn, calls the
useEmailTemplate method from EmailEnhancement.gsx.
Note: This example uses display keys that do not exist in the base configuration. You must
add the missing display keys to display.properties to see the
correct labels.
<?xml version="1.0"?>
<PCF
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../../pcf.xsd">
<Screen
editable="true"
id="CreateEmailScreen">
<Require
name="srcBean"
type="Activity"/>
<Require
name="docContainer"
type="Activity"/>
<Require
name="emailTemplateName"
type="String"/>
<Require
name="documentsToSend"
type="Document[]"/>
<Variable
initialValue="null"
name="documentToSave"
type="Document"/>
<Variable
initialValue="emailTemplateName == null"
name="noDefaultTemplate"
type="Boolean"/>
<Variable
initialValue="false"
name="saveAsDocument"
type="boolean"/>
<Variable
initialValue="false"
name="showCC"
type="boolean"/>
<Variable
initialValue="false"
name="showBCC"
type="boolean"/>
<Variable
initialValue="gw.api.util.LocaleUtil.getDefaultLanguageType()"
name="language"
type="LanguageType"/>
<Variable
initialValue="initializeSymbolTable()"
name="symbolTable"
type="java.util.Map<String,Object>"/>
<Variable
initialValue="new String()"
name="content"
type="String"/>
<Variable
initialValue="emailTemplateName == null ? null : fetchTemplate()"
name="template"
type="gw.plugin.email.IEmailTemplateDescriptor"/>
<Variable
initialValue="initNewEmail()"
name="NewEmail"
type="gw.api.email.Email"/>
<Toolbar>
<ToolbarButton
action="sendEmailToRecipients(NewEmail)"
available="true"
id="ToolbarButton0"
label="DisplayKey.get("Web.Activity.Email.SendEmail")"
visible="true"/>
<ToolbarButton
action="CurrentLocation.cancel()"
available="true"
id="ToolbarButton1"
label="DisplayKey.get("Web.Activity.Email.Cancel")"
visible="true"/>
<ToolbarDivider/>
<PickerToolbarButton
action="PickEmailTemplatePopup.push(createSearchCriteria())"
id="EmailWorksheet_UseTemplateButton"
label="DisplayKey.get("Web.Activity.Email.UseTemplate")"
onPick="template = PickedValue;
language = gw.api.util.LocaleUtil.toLanguageType(PickedValue.Locale);
executeTemplate(NewEmail)"
shortcut="P"
visible="noDefaultTemplate"/>
</Toolbar>
<AlertBar
id="NoDefaultTemplate"
label="DisplayKey.get("Web.Email.Template.NotFound", emailTemplateName)"
showConfirmMessage="false"
visible="emailTemplateName != null and noDefaultTemplate"/>
<DetailViewPanel>
<InputColumn>
<TypeKeyInput
editable="true"
id="Language"
label="DisplayKey.get("Web.EmailTemplateSearch.Language")"
required="true"
value="language"
valueType="typekey.LanguageType"
visible="LanguageType.getTypeKeys( false ).Count > 1 and emailTemplateName != null">
<PostOnChange
onChange="template = fetchTemplate(); executeTemplate(NewEmail)"/>
</TypeKeyInput>
<ListViewInput
editable="true"
id="ToRecipientLVInput"
label="DisplayKey.get("Web.Activity.Email.ToRecipients")"
labelAbove="true"
visible="true">
<Toolbar
visible="true">
<IteratorButtons
addVisible="true"
iterator="ToRecipientLV"
removeVisible="true"/>
<ToolbarDivider/>
</Toolbar>
<ListViewPanel
editable="true"
id="ToRecipientLV"
visible="true">
<RowIterator
autoAdd="true"
editable="true"
elementName="ToRecipient"
numEntriesRequired="1"
numEntriesToAdd="1"
toCreateAndAdd="var newEmailContact = new gw.api.email.EmailContact();
NewEmail.addToRecipient(newEmailContact); return newEmailContact;"
toRemove="NewEmail.removeToRecipient( ToRecipient )"
validationLabel="DisplayKey.get("Web.Activity.Email.ToRecipients")"
value="NewEmail.ToRecipients?.toTypedArray()"
valueType="gw.api.email.EmailContact[]">
<Row
editable="true">
<TextCell
editable="true"
id="ToName"
label="DisplayKey.get("Web.Activity.Email.Name")"
maxChars="60"
numCols="15"
value="ToRecipient.Name"/>
<TextCell
editable="true"
id="ToEmail"
label="DisplayKey.get("Web.Activity.Email.EmailAddress")"
numCols="15"
requestValidationExpression="VALUE == null ?
DisplayKey.get("Web.Activity.Email
.Error.AddressForToRecipientRequried") : null"
required="true"
value="ToRecipient.EmailAddress"/>
</Row>
</RowIterator>
</ListViewPanel>
</ListViewInput>
<ButtonInput
action="showCC = true"
id="ShowCCRecipients"
labelAbove="true"
value="DisplayKey.get("Web.Activity.Email.AddCCRecipients")"
visible="!showCC"/>
<ListViewInput
editable="true"
id="CcRecipientLVInput"
label="DisplayKey.get("Web.Activity.Email.CCRecipients")"
labelAbove="true"
visible="showCC">
<Toolbar
visible="true">
<IteratorButtons
addVisible="true"
iterator="CcRecipientLV"
removeVisible="true"/>
</Toolbar>
<ListViewPanel
editable="true"
id="CcRecipientLV"
visible="true">
<RowIterator
editable="true"
elementName="CcRecipient"
toCreateAndAdd="var newEmailContact = new gw.api.email.EmailContact();
NewEmail.addCcRecipient(newEmailContact); return newEmailContact;"
toRemove="NewEmail.removeCcRecipient( CcRecipient )"
value="NewEmail.CcRecipients?.toTypedArray()"
valueType="gw.api.email.EmailContact[]">
<Row
editable="true">
<TextCell
editable="true"
id="CcName"
label="DisplayKey.get("Web.Activity.Email.Name")"
numCols="15"
value="CcRecipient.Name"/>
<TextCell
editable="true"
id="CcEmail"
label="DisplayKey.get("Web.Activity.Email.EmailAddress")"
numCols="15"
required="true"
value="CcRecipient.EmailAddress"/>
</Row>
</RowIterator>
</ListViewPanel>
</ListViewInput>
<ButtonInput
action="showBCC = true"
id="ShowBCCRecipients"
labelAbove="true"
value="DisplayKey.get("Web.Activity.Email.AddBCCRecipients")"
visible="!showBCC"/>
<ListViewInput
editable="true"
id="BccRecipientLVInput"
label="DisplayKey.get("Web.Activity.Email.BCCRecipients")"
labelAbove="true"
visible="showBCC">
<Toolbar
visible="true">
<IteratorButtons
addVisible="true"
iterator="BccRecipientLV"
removeVisible="true"/>
</Toolbar>
<ListViewPanel
editable="true"
id="BccRecipientLV"
visible="true">
<RowIterator
editable="true"
elementName="BccRecipient"
toCreateAndAdd="var newEmailContact = new gw.api.email.EmailContact();
NewEmail.addBccRecipient(newEmailContact); return newEmailContact;"
toRemove="NewEmail.removeBccRecipient( BccRecipient )"
value="NewEmail.BccRecipients?.toTypedArray()"
valueType="gw.api.email.EmailContact[]">
<Row
editable="true">
<TextCell
editable="true"
id="BccName"
label="DisplayKey.get("Web.Activity.Email.Name")"
numCols="15"
value="BccRecipient.Name"/>
<TextCell
editable="true"
id="BccEmail"
label="DisplayKey.get("Web.Activity.Email.EmailAddress")"
numCols="15"
required="true"
value="BccRecipient.EmailAddress"/>
</Row>
</RowIterator>
</ListViewPanel>
</ListViewInput>
<InputDivider/>
<CheckBoxInput
editable="true"
id="SaveAsDocument"
value="saveAsDocument"
valueLabel="DisplayKey.get("Web.Activity.Email.SaveAsDocument")"/>
</InputColumn>
<InputColumn>
<TextInput
editable="true"
id="SenderName"
label="DisplayKey.get("Web.Activity.Email.SenderName")"
value="NewEmail.Sender.Name"/>
<TextInput
editable="true"
id="SenderEmail"
label="DisplayKey.get("Web.Activity.Email.SenderEmail")"
value="NewEmail.Sender.EmailAddress"/>
<TextInput
editable="true"
id="Subject"
label="DisplayKey.get("Web.Activity.Email.Subject")"
requestValidationExpression="VALUE == null ?
DisplayKey.get("Web.Activity.Email.Error.SubjectRequired") : null"
required="true"
value="NewEmail.Subject"/>
<TextAreaInput
editable="true"
id="Content"
label="template.ContentPrompt"
numCols="60"
numRows="10"
required="false"
value="content"
visible="template.Html">
<PostOnChange
onChange="executeTemplate(NewEmail)"/>
</TextAreaInput>
<TextAreaInput
editable="true"
id="Body"
label="DisplayKey.get("Web.Activity.Email.Body")"
numCols="60"
numRows="10"
requestValidationExpression="VALUE == null ?
DisplayKey.get("Web.Activity.Email.Error.BodyRequired") : null"
required="true"
value="NewEmail.Body"
visible="!template.Html"/>
<ListViewInput
editable="true"
id="AttachedDocuments"
label="DisplayKey.get("Web.Activity.Email.AttachedDocuments")">
<Toolbar>
<PickerToolbarButton
action="PickExistingDocumentPopup.push(docContainer)"
id="AddDocumentButton"
label="DisplayKey.get("Web.Activity.Email.AddDocument")"
onPick="NewEmail.addDocument(PickedValue)"
shortcut="A"
visible="true"/>
<IteratorButtons
addVisible="false"
iterator="AttachedDocumentsLV"/>
</Toolbar>
<ListViewPanel
editable="true"
id="AttachedDocumentsLV">
<RowIterator
editable="true"
elementName="AttachedDocument"
toRemove="NewEmail.removeDocument( AttachedDocument )"
value="NewEmail.Documents?.toTypedArray()"
valueType="entity.Document[]">
<Row>
<TextCell
editable="true"
id="Document"
label="DisplayKey.get("Web.Activity.Email.DocumentName")"
value="AttachedDocument.Name"/>
</Row>
</RowIterator>
</ListViewPanel>
</ListViewInput>
</InputColumn>
</DetailViewPanel>
<TemplatePanel>
<TemplatePanelContents><![CDATA[
<% if (template != null && template.Html) printContent(NewEmail.Body, false) %>]]>
</TemplatePanelContents>
</TemplatePanel>
<Code><![CDATA[function initializeSymbolTable() : java.util.Map<String,Object> {
return { "activity" -> srcBean }
}
function createSearchCriteria() : gw.api.email.EmailTemplateSearchCriteria {
var rtn = new gw.api.email.EmailTemplateSearchCriteria()
rtn.Language = language
rtn.AvailableSymbols = symbolTable.Keys?.toTypedArray()
return rtn
}
function initNewEmail() : gw.api.email.Email {
var rtn = new gw.api.email.Email()
if (documentsToSend != null) {
for (document in documentsToSend) {
rtn.addDocument( document )
}
}
if (template != null) {
executeTemplate(rtn)
}
return rtn
}
function fetchTemplate() : gw.plugin.email.IEmailTemplateDescriptor {
template = gw.plugin.Plugins.get(gw.plugin.email.IEmailTemplateSource)
.getEmailTemplate(gw.api.util.LocaleUtil.toLanguage(language), emailTemplateName);
if (template == null) {
noDefaultTemplate = true
throw new gw.api.util.DisplayableException(DisplayKey
.get("Web.Activity.EmailTemplate.Language", emailTemplateName, language))
}
return template
}
function executeTemplate( email : gw.api.email.Email) {
email.useEmailTemplate(template, { "activity" -> srcBean, "content" -> content })
}
function sendEmailToRecipients(emailToSend : gw.api.email.Email) {
var warnings = gw.api.email.EmailUtil.emailContentsValid(emailToSend)
if (warnings.length > 0) {
throw new gw.api.util.DisplayableException(warnings)
}
if (saveAsDocument) {
var templatePlugin = gw.plugin.Plugins.get(gw.plugin.document.IDocumentTemplateSource)
var emailSentDocTemplate = templatePlugin
.getDocumentTemplate("EmailSent.gosu.htm", gw.api.util.LocaleUtil.getDefaultLocale())
if (emailSentDocTemplate == null) {
throw new gw.api.util.DisplayableException("Could not save email as a document
because the \"EmailSent.gosu.htm\" does not exist!")
} else {
documentToSave = documentToSave != null ? documentToSave : new Document()
documentToSave.Name = emailToSend.Subject
documentToSave.MimeType = emailSentDocTemplate.MimeType
documentToSave.Type = typekey.DocumentType.get(emailSentDocTemplate.TemplateType)
documentToSave.Section = typekey.DocumentSection
.get(emailSentDocTemplate.getMetadataPropertyValue( "section" ) as String)
documentToSave.SecurityType = typekey.DocumentSecurityType
.get(emailSentDocTemplate.DefaultSecurityType)
documentToSave.Status = TC_FINAL
var recpName = emailToSend.ToRecipients.first().Name
documentToSave.Recipient = recpName == null ? emailToSend.ToRecipients.first().EmailAddress : recpName
documentToSave.Activity = docContainer
documentToSave.DateCreated = gw.api.util.DateUtil.currentDate()
documentToSave.Author = User.util.CurrentUser.DisplayName
documentToSave.Inbound = false
var paramMap = new java.util.HashMap()
paramMap.put("User", User.util.CurrentUser)
paramMap.put("Email", emailToSend)
paramMap.put("DateSent", gw.api.util.DateUtil.currentDate())
gw.document.DocumentProduction
.createAndStoreDocumentSynchronously(emailSentDocTemplate, paramMap, documentToSave);
}
} else if (documentToSave != null) {
documentToSave.remove();
}
gw.api.email.EmailUtil.sendEmailWithBody(srcBean, emailToSend);
// it didn't throw so reset email activity.EmailTemplate so that other templates can be used
if (emailTemplateName != null and srcBean typeis Activity) {
if (srcBean.EmailTemplate == emailTemplateName) {
srcBean.EmailTemplate = null
}
}
CurrentLocation.commit();
}]]></Code>
</Screen>
</PCF>
