User's GuideAdvanced FeaturesJavascript Usage in Emails

Javascript Usage in Emails

iPost’s JavaScript integration allows you to more easily create dynamic elements inside of your email content. With our integration you can display individual content for each subscriber creating an unique user experience with your brand.

How to insert JavaScript code

In order to use Server-Side JavaScript in an email, it needs to be wrapped in a <script> tag as follows:

<script type="itl/javascript">
message.write(“My content”);
</script>
Click to copy

In text content, an iTL expression must be used.

{\javascript \"
   message.write("Goodbye")
 \"}
Click to copy

When used in text content, the entire script must be contained in an iTL string.  Beware of using escaped double-quotes (\") within the script.

The use of this expression in message headers such as Subject is not currently available.

The <script>...</script> element and/or {\javascript ...} expression are removed from the content at the time they are executed, and do not appear in the message as delivered to the recipient.

Run-once Javascripts

The script tag may be provided the optional style attribute "--detail: once" to specify that the script should execute before content personalization for each recipient begins.

<script type="itl/javascript" style="--detail: once">
   message.write("<p>Hello, everybody.</p>")
 </script>
Click to copy

This also works for the iTL expression, using iTL parameter syntax:

 {\javascript \detail=once \"
   message.write("Greetings, all.")
 \"}
Click to copy

Content generated with message.write() in this context is inserted literally into the message, without link tracking or other automatic interpretation. Lookup(), Query(), and Webscrape() operations are allowed, but no per-recipient identifiers are available in SSJS during the interpretation of a run-once script.

You can use script.outerHTML to create content whose interpretation is deferred until send time:

<script type="itl/javascript" style="--detail: once">
script.outerHMTL += "<a href='https://www.ipost.com'>iPost</a>";
</script>

Although it refers to HTML, this also works for {\javascript ...} expressions in plain text.

Note: Run-once scripts currently execute during content validation, which may occur any time before the content is first used in a send. Depending on what type of automation or journey references the content, this may be hours, days, or even months in advance of sending.

Object Interface

Our JavaScript integration allows for some objects to be used inside emails, in order to generate and display custom content.

Contact

This object provides access to the data describing the recipient of the message. Unless specified below, assignments to the properties of this object do not have an effect outside of the Javascript scope. The contact object has no defined fields during run-once scripts.

Property Description
emailAddress The email address to which this message is being delivered. Altering this does not affect the actual delivery. It may become read-only in the future.
segmentId The segment ID to which this contact is assigned, typically as a result of an A/B split test or similar operation. This is not comparable to message.segmentId.
blob An encrypted string encoding the identity of the contact, typically for later use in iPost API calls. Assigning to this is not useful, it may become read-only in the future
data

This property is itself an object whose properties are the named data fields that are typically accessible through the iTL {\var:field} macro. Thus contact.data.first_name is equivalent to {\var:first_name}.

This enables operations such as

for (var f in contact.data) {
  message.write(f.toUpperCase() + " = " + contact.data[f]\n)
}

Assignments to properties of this object are not visible to iTL macros elsewhere in the message content, but are visible to other JavaScript elements. See contact.setData().

getData(field, fallback)
getData({name:field, encode:true}, fallback)
getData({name:field, decode:true}, fallback)
Invoke {\var:field fallback} to return the current value of the field independent of any assignments made to contact.data.field. If field does not have a value, return fallback.  The encode or decode booleans add or remove HTML entity encoding, respectively.
setData(field, value)
Assign a String or Number value to the field, thus making the new value visible to both JavaScript properties and iTL macros.  Replaces existing data in field or creates a new field.

It is an error to call setData() during a run-once script.
params Similar to contact.data, an array object containing the values accessed in iTL by {\emailparam:N} (Email Tracking Parameters). This may become read-only in the future. Changes to this array do not affect operations such as URL tracking that make reference to the values.  Note that contact.params[0] corresponds to {\emailparam:1} and so on.

Client

This object provides access to the data describing the client.

Property
Description
name
The name of the client.
token The iPost internal identifier (token) assigned to the client.
emailAddress The default reply address for the client.
postalAddress The postal address for the client.
senderDomain The Sender Domain for the send.  During run-once scripts, the senderDomain always refers to the client's global default domain.

Script

An object representing the <script> element that contains the executing script. It currently has four properties:

Property Description
script.line The line number in the source where the <script> tag appeared. Not currently available for plain text documents.
script.id A unique numeric ID for this script element.
script.detail

A string describing the runtime mode of the script, "recipient" by default, or "once" in a script using the "--detail: once" style.


script.outerHTML

This property is always null upon entry to a new script element and is normally read-only. However, in run-once scripts, it is writable and may be assigned a String of HTML text (including iTL references). This is validated in the same manner as a snippet, and then replaces the current script in the email content. This means that all automatic content transformations take place, such as converting URLs for link tracking. This new content appears after any content emitted by message.write() in the current script.

Note that validation errors in script.outerHTML cannot be trapped with try/catch() because validation does not occur until the script element has finished.


Message

When processing content for email sending, this represents the current message body part in which the script appears. In other contexts this property is undefined.

Property Description
isHTML Boolean
isText Boolean
isF2F Boolean
inBrowserView Boolean
segmentId The segment ID assigned to this message content, identifying the snippet or other dynamic subsection currently being processed.
header

A set of properties describing the message header. Currently there are only four of these:

message.header.replyAddress

message.header.displayFrom

message.header.subject

message.header.from

These properties may be assigned directly, but doing so does not alter the header values outside of the current script context. They may become read-only in the future. To change the external message header, use the message.setHeader() function.

When message.inBrowswerView is true, only message.header.subject is defined. In run-once scripts, none of these values is defined.

setHeader(name,value)

Assign to the delivered message any of the four properties of message.header. Note name is a string, not an LValue. If any of "replyAddress", "displayFrom", or "from" is updated, the other two are updated to correspond.

When message.inBrowswerView is true, only "subject" may be set, any other header changes are silently ignored. It is an error to call setHeader() during a run-once script.

Other headers are not supported at this time.

message.params
An array object containing a context-dependent subset of the values accessed in iTL by {\emailparam:N}. In run-once scripts, only "Static String" parameters are available, plus the "Sytem Field" values "Email Name", "Email Subject", and "Vendor Name" (that is, values that do not depend on a recipient identity). Otherwise, this is the same as the contact.params (above).
write(text) Insert the text into the current message body part. This occurs as soon as the function is invoked. Text written in this way replaces the <script>...</script> element where it appears in the message body, so that no scripting code appears in the final delivered message. Multiple calls to message.write() append to one another.  Text added with message.write() precedes the script.outerHTML in the final output.

a(url,text,attributes)

img(url,text,attributes)

Return strings of HTML for <A href=url>text</A> and <IMG src=url alt=text> elements, with tracked representations of url. See Link() below. These functions throw a generic Error if the URL schema prevents tracking (but do not do so during UI Preview).

The attributes object (hash) is optional and may specify other attributes of the returned HTML tag, such as "name", "style", etc. For message.img, text (the alt text) is also optional, but if you want to provide the attributes you must explicity use undefined as the second argument.

Note you can do:

 var clickable = message.a(targetURL,message.img(imageURL))

but it's not usually necessary as view tracking is handled elsewhere.

The result also contains heat map markup when displayed in the Reports UI.

In plain text documents, message.img() returns text in square brackets, but ignores url, and message.a() returns text followed by a space followed by the tracked representation of url.  The attributes object may be used to attach a name to the link for reporting purposes, but no attributes appear in the output.

In run-once scripts these functions return appropriate markup but do not convert the URLs for tracking.  To cause the links to be tracked, include them in script.outerHTML.

links

The message.links property includes three functions, each of which returns an encoded URL for an action related to the message.  If used in run-once scripts, they return iTL references to the corresponding functions, which may then be used in script.outerHTML but are not suitable for message.write().

message.links.view(format)

The view-in-browser link for the message. The format is optional, having values "html" or "text".

message.links.forward()

A link to the forward-to-friend form for the message.

message.links.optout(oneclick)
An opt-out link for the recipient. If the Boolean value oneclick is true, returns a one-click link, otherwise a link to the preferences page where the contact confirms his choice. For compatibility with RFC8058, in order to be effective, one-click links must be sent with a form POST action rather than an anchor GET action.

These methods should not be used in run-once scripts, the URLs returned do not contain contact identification for the message recipient.

There are also four attributes that may be available when the message is sent by injection of a contact into a journey. Whether they are defined depends on the journey configuration.

message.formdata.submitterIP

message.formdata.submitTime

Information about the form submission that injected this contact.

message.formdata.newEmailAddress

message.formdata.oldEmailAddress

The new and previous email addresses in the event of an address change.

None of these are defined in run-once scripts. 

These attributes may become read-only in the future.

iTL

An object providing low-level interfaces to the iTL engine. It currently has six function properties, get, set, call, ref, literal, and log.

itl.get(variable)

Returns the value of an iTL global named by the String variable, either one previously defined in iTL with{\define \variable value}or one initialized by itl.set(variable,value)

itl.set(variable,value)

Store value in the in the iTL global named by the String variable.  Note that this does not make \variable visible to the iTL compiler, so in order to use the variable in iTL you either must use the {\jsget variable} macro, or must have previously declared the variable name with {\define \variable ...}.

Compare contact.setData(field,value) which supports only String and Number values.

itl.call(macro,named,rest...)

Attribute Description
macro
Invoke the iTL macro macro. The macro name should not have a leading backslash. Throws ReferenceError if macro is not valid.
named An object (hash table) of any named arguments to the macro. The names should omit the leading backslash. Pass empty braces if there are no useful named arguments.
rest... The arguments forming the "rest-list", if any.

For example:

var text = itl.call("wrap", { margin: 10 }, 
                     "This is a sentence to reformat.")
Click to copy

Note that itl.call immediately interprets its argument macro. When that macro returns predefined content such as snippets, headers, and footers, any and all embedded iTL macros are processed and replaced by their result text, and no special HTML interpretation or validation is performed as part of itl.call.

if (my_var == 1) snippet = itl.call("itl_snippet", {id: 123});
else if (my_var == 2) snippet = itl.call("itl_snippet", {id: 456});
else if (my_var == 3) snippet = itl.call("itl_snippet", {id: 789});

message.write(snippet);
Click to copy

In the example above, remember that those snippets loaded via itl.call() are not subject to HTML interpretation.  That means that, for example, <script> tags are returned as-is, so you cannot nest SSJS in snippets by this method.

Note that the following iTL forms may not be called this way.  As a workaround to these restrictions, see script.outerHTML above.

iTL Forms Description
\define, \set!, \if, \and, \or, \cond, \while, \lambda, \let, \let*
Syntax tokens must appear directly in the content
{\var:field}
See contact.data below

{\apply function ...}

{\foreach function list}

{\funcall function ...}

These cannot be used because there is no way to construct a reference to an iTL function from within Javascript

{\document_segment ...}

{\itl_dynamic ...}

{\itl_rss ...}

These require validation-time content processing, not currently available in send-time SSJS.
{\lookup ...}
See Lookup
{\query ...}
See Query
{\webscrape ...}
See Webscrape
{\rss ...}
Not yet available 

itl.ref(string)

The string is syntax checked as a valid iTL identifier.  Returns a String having the form of an iTL reference, specifically, the same string prefixed with a backslash.

 This is mostly useful in plain text documents where the entire script must be contained inside an iTL literal, and when constructing script.outerHTML content (see above).

itl.literal(string)

Returns the string in the form of an iTL literal string, that is, prefixed and suffixed with a backslash-double-quote pair.

  Useful in plain text documents where it is difficult to nest a literal inside the body of the script, and for script.outerHTML.

itl.log(strings...)

Output a timestamped string (or list of strings) to the log, with the source line number appended.

Currently, log output is accessible only to iPost staff, so use this for debugging only when requested to do so.

Function Interface

There are some functions callable at the top level, without reference to an object. In this sense they act like object constructors, but return a base object type.

JSON(object)

Return a string that is the JSON representation of the object.

JSON.parse(string)

Converts a JSON string back into an object. This is a convenience function; the following two examples should be equivalent: 

 var jsonString = '{ "one": "1", "two": "2" }';
 var obj = JSON.parse(jsonString); // Example 1
 eval("var obj = "+jsonString);    // Example 2

The eval form preserves Number values, whereas JSON.parse converts all non-structured data to String.

Returns an object representing a tracked URL. The type is a string, typically one of "a" (for anchor), or "img", indicating the context of the URL. The link() method of that object returns the encoded and tracked representation of url, or throws an Error if the URL schema prevents tracking. Usage is for example:

var tracked = Link("http://www.ipost.com","a");
 message.write("<a href='"+tracked.link()+"'>Click Here</a>");
Click to copy

This is usually better done with message.a(), but there may be cases in which a tracked URL is wanted without the HTML markup. 

In run-once scripts the link() method returns an iTL expression representing the link, suitable for use in script.outerHTML. However, note that the content of script.outerHTML is subject to automatic link rewriting, so Link() is not usually needed.

Note regarding trackUrls in all following: A best-guess search is used to identify and extract URLs from text values. Although this is robust, the URL format and surrounding context may affect the results. If a value is known to represent only a URL, it is usually better to explicitly apply Link() rather than trackUrls.

Lookup(tableName,searchFields,orderby,limit)

Returns an object defining a simple search of a single Custom Data Table. The searchFields are required and are represented by an Object with property names corresponding to column names from the table and values to be matched against the table rows. All matches are exact, but are case-insensitive unless otherwise determined by the column definition for the table.

The tableName must be a String and may be of the form "db.table" where "db" names an alternate database. Currently only two database names are valid: The system tables database (ID_imm), and the client's customizable database (ID_cdt), which is selected by default.

The optional orderBy is an Object with properties corresponding to columns and values "asc" or "desc" for the direction of the ordering. The optional limit determines the maximum number of rows to return.

The returned object has a single function property:

execute(trackUrls) 

Performs the table search and returns an Array. Each element of that Array is an Object corresponding to one matched row from the table. If no rows match, the returned Array is empty. The properties of each object are the column names from the table.

If the optional Boolean trackUrls is true, any text-typed values in the returned rows are scanned for URL references, and those references are converted as described for the Link().link() method.

Example: 

 var rIndexArray = Array("ASU", "DEL", "JMU", "NYU", "OCM");
 for (var i in rIndexArray) {
   var look = Lookup("school_branding", {school_code: rIndexArray[i]});
   var result = look.execute();
   if (result.length) {
     var school = result[0];
     message.write(rIndexArray[i]+" is code for "+school.school_name);
   }
 }


Lookup() throws errors for incorrect parameter usage, such as tableName not a String or limit not a number. It's an error to use trackURLs = true in run-once scripts in the execute(), get(), and post() functions.

Query(queryId,keyField,bindings,limit)

Alternately: Query({id:queryId,key:keyField,bind:bindings,limit:limit})

Returns an object representing a query defined in the Enterprise SQL Queries user interface. All arguments except the queryId are optional. The arguments may be passed either as properties of an object, or as positional arguments as shown. In the positional form, if you wish to provide bindings without using a keyField, you must explicity use undefined as the second argument.

The positional form is a convenience most useful when the only argument is the queryId, thus:

var query = Query(74);

The keyField is used by the execute() method (see below) to structure the query results. If a keyField is defined, rows are unordered, otherwise they are ordered as defined in the query.

The bindings are contained in an object whose property names are the names of variables declared in the query definition, and the limit declares the maximum number of rows to return, which defaults to, and may never exceed, 100 rows. The bindings property names must include the "@" prefix used for variable naming in SQL, so they should be quoted as strings (see example below).

execute(trackUrls,newBindings) 

Runs the query specified by queryId. If the optional Boolean trackUrls is true, any text-typed values in the returned rows are scanned for URL references, and those references are converted as described for the Link().link() method. Optional newBindings may be provided to replace the bindings, in the same format. 

The return value is determined by the keyField

  • If the query results in no rows, the result is the undefined value. This differs from iTL {\query} which returns an empty list, but maintains the semantic that a query of no result is Boolean false.
  • If the keyField is undefined, or does not refer to a name that is present in the SELECT list of the query, the result is an Array. Each element of that Array is itself an Array corresponding to one matched row from the table, following the ORDER BY of the query (if any). The order of the fields is as defined in the SELECT list.
  • Otherwise the result is an Object whose properties are the values of the keyField from each row. The value of each property is an Object representing one row from the query, as described above for Lookup().execute(). Note that the keyField results are not required to be syntactically valid as unquoted property names, so the object.property syntax is not always usable to reference these rows. Use object["property"] format when necessary. 

Example:

// In this example, queryID = 74 has "SET @qEmail = ..."
// and "SELECT email, first_name, last_name FROM ..."
// ITL: {\query \id=74 \bind={{@qEmail {\recipient_addr}}} \limit=1}

var query = Query({id:74,bind:{"@qEmail": contact.emailAddress},limit:1});
var result = query.execute();
if (result) {
   // keyField was undefined, so result is an Array, and limit == 1
   var row = result[0];
   // Output: email last,first
   message.write(row[0]+"&nbsp;"+row[2]+","+row[1]);
}

// Same query, alternate format, using keyField = "email" and no limit
// ITL: {\query \id=74 \key=email \bind={{@qEmail {\recipient_addr}}}}

var query = Query(74,"email",{"@qEmail": contact.emailAddress});
var result = query.execute();
if (result) {
   var row = result[contact.emailAddress];
   message.write(row.email+"&nbsp;"+row.first_name+","+row.last_name);
}

Query() throws errors for incorrect parameter usage, such as keyField not a String or limit not a number. It's an error to use trackURLs = true in run-once scripts in the execute(), get(), and post() functions.

Note: If the keyField is not unique for the rows in the query result, only one of the possible matching rows is returned in the result Object. Which one of the possible rows, is indeterminate.

Note: The query should properly name its result elements, for example by use of the SELECT element AS name syntax, if it is meant to be called with a keyField defined.

Webscrape(url,params)

Returns an object defining a remote content source. The only valid URI schema for url are httphttps, and ftp, other URLs throw an error. This is based on the iTL {\webscrape} macro, see the iTL documentation for additional details.

The optional params object defines form data for POST requests.

The returned object has two function properties, each of which returns a String containing the answer from the remote server:

get(trackUrls) 

Issues a GET request. If url does not have a search string (aka query parameters) and params were provided, that form data is converted into a search string. The optional Boolean trackUrls (default false) determines whether the retrieved content is searched for URL references, which if found are encoded as described above for Link().link()

post(trackUrls, headers) 

Issues a POST request. If url has a search string and no params were provided, the search string is converted into form data. Boolean trackUrls is as for get(). The optional headers object defines additional headers for the request, such as authentication tokens, etc.

Behavior when both a search string and form data are present is determined by the remote server.

Note headers are not supported for GET requests, because the iTL {\webscrape} supports them only for POST.

Both of these functions will throw an error if there is any problem either retrieving the content, or converting it for inclusion in the message source. Note that unlike raw iTL {\webscrape}, this interface does not provide for "fallback content" to suppress these errors, so use try/catch() if a fallback is desired.

It's an error to use trackURLs = true in run-once scripts in the execute(), get(), and post() functions.

XML(object)

Return a string that is a simple XML representation of the object. Throws SyntaxError if object does not represent a node tree.

XML.parse(string)

Converts an XML string into an object. This may be used to parse HTML content, but the resulting object tree may be ambiguous, so may not reproduce the original if converted back into HTML.

The parse is forgiving of unmatched < and of unstructured text preceding or following balanced XML tags, but throws SyntaxError for more serious errors such as a closing tag with no corresponding open.

Syntax Elements

Primitives

Object Definition
Boolean true
false
LValue

An assignable identifier, as found on the left side of an . If you simply write

<script type="itl/javascript">contact.data.name</script>

that is an LValue identifying the name property of contact.data. If you write

<script type="itl/javascript">
  contact.data.name = "Marvin"
</script>

that assigns "Marvin" to the name property. If you write

<script type="itl/javascript">
  message.write(contact.data.name)
</script>

then the current value of the name property is written.

Null

Class for the null value (as distinct from undefined).

null
Number A simple wrapper around the low-level implementation of numbers.
String A simple wrapper around the low-level implementation of strings.
Undefined

Class for the undefined value.

undefined

Classes and Methods

Class
Description
Object The other classes all inherit the base methods from Object.
Array
Boolean
Date
Error Including:
  • RangeError
  • SyntaxError
  • TypeError
  • URIError
Function
Math
Number
RegExp
String
URL