Scriptlets
Table of Contents
- 1 Table of Contents
- 2 Description
- 3 Formal Description
- 4 Language Elements
- 5 External Data
- 5.1 External JSON
- 5.1.1 Feed Structure
- 5.1.2 Syntax for retrieving data
- 5.1.3 Syntax Example
- 5.1.4 Data Usage
- 5.2 External HTML
- 5.1 External JSON
- 6 Examples
- 6.1 Multiple Statements
- 6.2 Comments
- 6.3 Hashes
- 6.4 Standard hashes
- 6.5 Maps
- 6.5.1 Example: Shoppingcart
- 6.6 Primitives
- 6.7 Variables
- 6.8 Dates, Datetimes
- 6.9 Sequences
- 6.10 Conditional Statements
- 6.11 Loops
- 7 Usecase Examples
- 8 Changelog
Description
“Scriptlets” is the name of our programming language used within Maileon newsletters to realize extensive requirements on data processing and output. Scriptlets allow for example generating random numbers or UUIDs for each contact within a sendout in order to attach it to some link. It allows generating an (MD5) hash of data like the email address or encrypt data with some given key and supports complex processing of data like parsing a string as a datetime object, adding 7 days and printing it in some other format. Also accessing external data sources for each individual contact is possible in order to e.g. display individual products for each contact.
Thus, Scriptlets support a huge number of language elements and even if it is not possible to create an infinite loop, you can use loops, e.g. when iterating over the items of some shopping cart in order to calculate the overall sum or to display the items in a newsletter.
The formal description is provided as BNF in the next section, however, most readers will benefit at the beginning more of some unformal description or the examples later on. Scriptlets are always wrapped in double square brackets [[ ]]. Inside the brackets, a Scriptlet is started with a “%” sign to avoid mixing up regular Maileon-Mergetags and Scriptlets. For Scriptlets a preorder syntax has been chosen, this means that the operator is in the beginning of an expression and the parameters follow behind, separated by a whitespace “ “. If an parameter is an expression with some operator itself, it has to be wrapped in single round brackets ().
Simple examples:
[[ % 'Hello world!']]
[[ % md5 (contact 'EMAIL')]]
For date and time formats please refer to https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/SimpleDateFormat.html
Formal Description
This section defines the BNF of the language elements.
<expr> ::= <void_expr> | <none_void_expr>
<void_expr> ::= <conditional_statement> | <foreach_statement>
<conditional_statement> ::= <if_statement> | <elseif_statement> | <else_statement> | <endif_statement>
<if_statement> ::= "if" {logical_expr>
<elseif_statement> ::= "elseif" {logical_expr>
<else_statement> ::= "else"
<endif_statement> ::= "endif"
<foreach_statement> ::= <foreach_expr> | <end_foreach> | break
<foreach_expr> ::= "foreach" <var_expr> "in" <sequence_expr>
<end_foreach> ::= "endforeach"
<none_void_expr> ::= <typed_expr> | <untyped_expr>
<typed_expr> ::= <string_expr> | <date_expr> | <datetime_expr> | <logical_expr> | <numeric_expr> | <sequence_expr>
<untyped_expr> ::= <assign_expr> | <hash_expr> | <var_expr>
<assign_expr> ::= "set" <var_expr> <none_void_expr>
<var_expr> ::= "$" litteral
<string_expr> ::= string | <string_function> | <untyped_expr>
<numeric_expr> ::= number | <numeric_function> | <untyped_expr>
<logical_expr> ::= boolean | <logical_function> | <untyped_expr>
<sequence_expr> ::= sequence | <sequence_function> | <untyped_expr>
<date_expr> ::= <date_function> | <untyped_expr>
<datetime_expr> ::= <datetime_function> | <untyped_expr>
Language Elements
The 'mine' Function
mine
Description: Causes the message generation to fail. Can be used e.g. to not send an automated transaction mail under certain circumstances.
mine <string>
Description: Same as “mine” without parameter but fires a “named” personalization error, if triggered.
String Functions
to_string <none_void_expr>
lower_case <string_expr>
md5 <string_expr>
capitalize <string_expr>
normalize_space <string_expr>
reverse <string_expr>
trim <string_expr>
uncapitalize <string_expr>
upper_case <string_expr>
default_if_blank <string_expr> <string_expr>
default_if_empty <string_expr> <string_expr>
remove <string_expr> <string_expr>
remove_end <string_expr> <string_expr>
Description: Removes the second string from the end of the first string
remove_end_ignore_case <string_expr> <string_expr>
remove_start <string_expr> <string_expr>
remove_start_ignore_case <string_expr> <string_expr>
substring <string_expr> <numeric_expr> <numeric_expr>
substring_after <string_expr> <string_expr>
substring_after_last <string_expr> <string_expr>
substring_before <string_expr> <string_expr>
substring_before_last <string_expr> <string_expr>
substring_between <string_expr> <string_expr> <string_expr>
random_alphabetic <numeric_expr>
random_alphanumeric <numeric_expr>
random_numeric <numeric_expr>
to_string_on_off <logical_expr>
to_string_true_false <logical_expr>
to_string_yes_no <logical_expr>
replace <string_expr> <string_expr> <string_expr>
replace_once <string_expr> <string_expr> <string_expr>
center <string_expr> <numeric_expr> <string_expr>
abbreviate <string_expr> <numeric_expr>
Description: Cuts down the string to the given length INCLUDING the three abbreviation indicating dots. If nothing will be cut, the dots will not be added.
[[ % abbreviate '123456' 6]] will be evaluated to '123… '
Thus, the length MUST be greater or equal to 4.
abbreviate_middle <string_expr> <string_expr> <numeric_expr>
repeat <string_expr> <numeric_expr>
random <numeric_expr> <string_expr>
boolean_to_string <logical_expr> <string_expr> <string_expr>
join <sequence_expr> <string_expr>
concat <sequence_expr>
unescape_html <string_expr>
date_to_string <date_expr> <string_expr> <string_expr>
datetime_to_string <datetime_expr> <string_expr> <string_expr>
format_date <string_expr> <string_expr> <string_expr> <string_expr>
format_datetime <string_expr> <string_expr> <string_expr> <string_expr>
aes_encrypt_hex <string_expr> <string_expr>
format_number <numeric_expr> <string_expr> <string_expr> <numeric_expr>
Warning: if the number comes from a custom contact field (type float) and is not set, it returns the STRING value “NaN”, which will cause the formatting to fail. Use an “if” around the expression:
url_encode <string_expr>
Description: Encodes a string as a URL parameter that can be passed
url_decode <string_expr>
Description: Decodes a string as URL parameters that will be interpreted
assigned_voucher <string-literal>
Description: Print voucher code, parameter is pool name (not the ID)! Fails if voucher does not exist.
assigned_voucher <string-literal> <string-literal>
Description: Print voucher code, parameter is pool name (not the ID) + fallback value! Fails if voucher does not exist.
voucher <string-literal> <string-literal>
Description: Print voucher code, parameter is pool ID (as a string) + fallback value! Fails if voucher does not exist.
conditional_content <string-literal>
Description: Print COCO ruleset result, parameter is rulset name (not the ID)! Fails if the ruleset does not exist. Default COCO rulesets cannot be referred to as their representation is language dependent.
Logical functions
As Maileon uses a three state value for Booleans (not set, true or false), these methods define a fallback behavior, which is added in [brackets] behind the expression. They will return this result, if e.g. a custom field is not set. Methods without annotation will fail if the field is empty, so a check for existence is mandatory.
to_boolean <none_void_expr>
exists <none_void_expr>
or <logical_expr>*
This method checks every expression, even if earlier expressions evaluated to truelogical_or <logical_expr>*
or with early abortand <logical_expr>*
This method checks every expression, even if earlier expression evaluated to falselogical_and <logical_expr>*
and with early abortnegate <logical_expr>
xor <logical_expr>*
is_all_upper_case [false]
is_boolean <none_void_expr> [false]
is_number <none_void_expr> [false]
is_date <none_void_expr> [false]
is_datetime <none_void_expr> [false]
is_string <none_void_expr> [false]
is_time <none_void_expr>
is_sequence <none_void_expr> [false]
contains_whitespace <string_expr> [false]
is_all_lower_case <string_expr> [false]
is_alpha <string_expr> [false]
is_alphanumeric <string_expr> [false]
is_alphanumeric_space <string_expr> [false]
is_alpha_space <string_expr> [false]
is_blank <string_expr> [true]
is_empty <string_expr> [true]
is_not_blank <string_expr> [false]
is_not_empty <string_expr> [false]
is_numeric <string_expr> [false]
is_numeric_space <string_expr> [false]
is_whitespace <string_expr> [false]
string_to_boolean <string_expr> [false]
contains <string_expr> <string_expr> [false]
contains_ignore_case <string_expr> <string_expr> [false]
ends_with <string_expr> <string_expr> [false]
ends_with_ignore_case <string_expr> <string_expr> [false]
starts_with <string_expr> <string_expr> [false]
starts_with_ignore_case <string_expr> <string_expr> [false]
equals <string_expr> <string_expr> [false]
Description: Compares two STRINGS for equality. Not applicable, if variable content is numeric, in this case use “eq”
equals_ignore_case <string_expr> <string_expr> [false]
is_false <logical_expr>
is_not_false <logical_expr>
is_not_true <logical_expr>
is_true <logical_expr>
negate <logical_expr>
seq_contains <sequence_expr> <none_void_expr> [false]
seq_contains_any <sequence_expr> <sequence_expr> [false]
seq_contains_none <sequence_expr> <sequence_expr> [true]
seq_contains_all <sequence_expr> <sequence_expr> [false]
Description: Checks if sequence1 contains all elements of sequence2
equals_any(_ignore_case) <string-expr> <sequence-expr>
equals_none(_ignore_case) <string-expr> <sequence-expr>
contains_any(_ignore_case) <string-expr> <sequence-expr>
contains_none(_ignore_case) <string-expr> <sequence-expr>
contains_all(_ignore_case) <string-expr> <sequence-expr>
starts_with_any(_ignore_case) <string-expr> <sequence-expr>
starts_with_none(_ignore_case) <string-expr> <sequence-expr>
ends_with_any(_ignore_case) <string-expr> <sequence-expr>
ends_with_none(_ignore_case) <string-expr> <sequence-expr>
gt <numeric_expr> <numeric_expr>
ge <numeric_expr> <numeric_expr>
eq <numeric_expr> <numeric_expr>
Description: Compares numeric values, not strings
ne <numeric_expr> <numeric_expr>
lt <numeric_expr> <numeric_expr>
le <numeric_expr> <numeric_expr>
is_preference_true <string> <string>
Arguments: category name, preference name
preference_has_value <string> <string>
Arguments: category name, preference name
preference_has_no_value <string> <string>
Arguments: category name, preference name
preference_has_no_value_or_false <string> <string>
Arguments: category name, preference name
is_preference_false <string> <string>
Arguments: category name, preference name
is_any_preference_true <string>
Arguments: category name
is_matched_by_filter <string >
Arguments: Parameter is the name of the filter, not its ID! No failure if filter does not exist but returns false. Works reliably in regular mails only but might represent outdated results in transactional or DOI confirmation mails.
is_not_matched_by_filter <string >
Arguments: Parameter is the name of the filter, not its ID! No failure if filter does not exist but returns false. Works reliably in regular mails only but might represent outdated results in transactional or DOI confirmation mails.
Numeric Functions
to_number <none_void_expr>
add <numeric_expr> <numeric_expr>
length <string_expr>
mul <numeric_expr> <numeric_expr>
sub <numeric_expr> <numeric_expr>
div <numeric_expr> <numeric_expr>
pow <numeric_expr> <numeric_expr>
ceil <numeric_expr>
floor <numeric_expr>
round <numeric_expr>
abs <numeric_expr>
max <sequence_expr>
min <sequence_expr>
sum <sequence_expr>
seq_size <sequence_expr>
mod <numeric_expr> <numeric_expr>
datetime_to_time <datetime_expr>
Description: Translates a datetime into a timestamp
date_to_time <date_expr>
Description: Translates a date into a timestamp
parse_number <string_expr> <string_expr> <string_expr>
increment <numeric_expr>
decrement <numeric_expr>
Sequence Functions
split <string_expr> <string_expr>
split (contact 'listField' ';')
csv <string_expr>
seq_add_all <sequence_expr> <sequence_expr>
seq_add <sequence_expr> <none_void_expr>
Description: Add an element to a sequence. This method does not change the input sequence, make sure to save the result
seq_replace <sequence_expr> <sequence_expr>
partition <sequence_expr> <numeric_expr>
reverse_seq <sequence_expr>
shuffle <sequence_expr>
select_true_preferences <string>
Arguments: category name - return sequence of preference names that are true
select_false_preferences <string>
Arguments: category name - return sequence of preference names that are false
Object Functions
item <sequence_expr> <numeric_expr>
Description: Selects the n-th item from a sequence. The index starts with 0 for the first item.
Date Functions
now
to_date <string_expr> <string_expr>
cast_date <string_expr>
time_to_date:<numeric_expr>
Datetime Functions
date_sent
Description: The datetime of the sendout, also works for triggermails
to_datetime <string_expr> <string_expr>
cast_datetime <string_expr>
time_to_datetime <numeric_expr>
add_seconds <date_or_datetime_expr> <numeric_expr>
add_minutes <date_or_datetime_expr> <numeric_expr>
add_hours <date_or_datetime_expr> <numeric_expr>
add_days <date_or_datetime_expr> <numeric_expr>
add_weeks <date_or_datetime_expr> <numeric_expr>
add_months <date_or_datetime_expr> <numeric_expr>
add_years <date_or_datetime_expr> <numeric_expr>
External Data
Maileon can retrieve external data, either as JSON or plain HTML. The following facts and restrictions are valid for both features.
Maileon uses caching strategies to reduce the amount of request. Please make sure that the server always returns the same response for the same request within one sendout. As URLs can contain variables it might result in a lot of different URLs and thus, a lot of requests. Make sure your server can process the request fast enough as it will delay the sendout process. If a service times out, the mailing(s) the response was meant for are not processed any further and are reported as “failed sendouts”.
Request Type | GET |
Number of parallel requests | bis zu 40 |
Request Cache | Per thread and per “working packet” (= 5.000 contacts) |
Response Code | 200 |
Redirects | Not allowed |
Authorization | Optional, Basic Auth in URL format |
Maximum Response Size | 3 MB |
Timeout | 5 Seconds |
URL Restrictions | Please be aware that URLs like “localhost” or “127.0.0.1” neither make sense, nor are accepted |
External JSON
Feed Structure
External JSON can be used to request data from external systems that is processed and rendered into the mailing. Please make sure that you do not return an array, directly, always return an object and there an attribute with an array content. I.e. do not return
But wrap it in an object with a named attribute, e.g.:
Syntax for retrieving data
{varName}
is a free choosable name for the variable, the content is available in, later. It must start with a character. {url_with_personalization}
is the url with protocol (https://) and personalizations e.g. from contactfields need to be in Mergetag-Syntax with only a single bracket, e.g. the E-Mail-Hash would be: [MD5|CONTACT|EMAIL]
Syntax Example
In this case the data of the “stream” will be available in variable “myData” and will submit some path parameter from a customfield called “jsonfile”. Variables can of course also used as query parameters (sometimes referred to as GET parameters).
Data Usage
From here, Scriptlets can be used to access the values using “ext_json” method, e.g.:
To save the array into variable myVar:
To save the first array element from myVar (example above) into variable myElement
Or simply use loops to display all elements
External HTML
The HTML provided by an external service provider will be included in Maileon as returned. Make sure to not return invalid HTML or HTML that causes display problems in Mail clients.
Please be aware that dynamic fields within returned HTML are not filled by Maileon. In other words: if a mergetag like [[CONTACT|FIRSTNAME]] is included in the returned HTML, it will not be processed by Maileon.
Syntax for retrieving data
Examples
Multiple Statements
Comments
Hashes
Standard hashes
As SUBJECT or NAME are standard values for mailings, you can also access own custom values of mailings with just specifying the key name, e.g. [[ % mailing 'test' ]]
Maps
If the value of $var is a map (key-value pairs) then you can access some value by calling:
Example: Shoppingcart
Primitives
Output: truestring-12.34
Variables
Output: aA
Dates, Datetimes
Current date and time
Print date of yesterday
Sequences
Output: axbxcxaxbxcxd
Conditional Statements
Loops
Output: abcdef12
Usecase Examples
Calculate MD5 hash over a concatenation of the email address, a transactional field “custom2” and “custom3”
AES encryption of contact field “custom1” with key 0123456789abcdef.
Please note: the key length has to be exactly 128 bit (16 byte, in this case 16 characters).
Add 4 Weeks to the date when the mailing has been sent, this works for regular mailings only. For transaction mailings it will be the date of activation, see “date_send”
Parse String from a transaction as number, take absolute value and print it with 2 digits precission
Parse a date like "2019-11-06T02:00:00Z", and print it as "06.11.2019":
Parse a date like "2019-11-06T02:00:00.000+0200", and print it as "06.11.2019":
Check if transaction variable that is given as string is larger or smaller than 0 and print it
Generate UUID v4
Print Birthday
Add 3 months to birthday:
Add 3 months to sendout date:
Count up variable in a loop by 1:
Unescaping HTML to display items
Displaying Magento Price Reductions
Displaying Shopware Price Reductions
Price Based on Language
Display 3 Elements out of a large Sequence
Calculate Age from Birthday
Print number of days till a certain date
Changelog
Version 1.7
Added example
Version 1.6 08.04.2022
Added new string method: voucher
Added description for external JSON and HTML
Version 1.5 26.10.2021
Added examples
Adde new datetime methods (sendout_date)
Adde new string methods (url_encode, url_decode, assigned_voucher, conditional_content)
Adde new sequence methods (partition, shuffle, reverse)
Adde new numeric methods (increment, decrement)
Adde new boolean methods (is_matched_by_filter, is_not_matched_by_filter, equals_any(_ignore_case), equals_none(_ignore_case), contains_any(_ignore_case), contains_none(_ignore_case), contains_all(_ignore_case), starts_with_any(_ignore_case), starts_with_none(_ignore_case), ends_with_any(_ignore_case), ends_with_none(_ignore_case))
Added default behavior for boolean expressions when boolean value is not set (neither true nor false)
Added preference methods (is_preference_true, preference_has_value, preference_has_no_value, preference_has_no_value_or_false, is_preference_false , select_true_preferences, select_false_preferences, is_any_preference_true)
Added named mine statements
Version 1.4 (27.09.2019)
New layout for documentation
Version 1.3 (07.02.2019)
added parse_number: {string_expr> {string_expr> {string_expr>
added format_number: {numeric_expr> {string_expr> {string_expr> {numeric_expr>
added examples
Version 1.2 (28.03.2017)
added substring <string_expr> <numeric_expr> <numeric_expr>
Version 1.1 (29.07.2016)
added datetime_to_time <datetime_expr>
added date_to_time <date_expr>
added time_to_datetime <numeric_expr>
added time_to_date <numeric_expr>
added add_seconds <date_or_datetime_expr> <numeric_expr>
added add_minutes <date_or_datetime_expr> <numeric_expr>
added add_hours <date_or_datetime_expr> <numeric_expr>
added add_days <date_or_datetime_expr> <numeric_expr>
added add_weeks <date_or_datetime_expr> <numeric_expr>
added add_months <date_or_datetime_expr> <numeric_expr>
added add_years <date_or_datetime_expr> <numeric_expr>