Composite type syntax
Array indexing and slicing
MQL uses zero indexing for arrays. From 0 up to length(array) - 1, negative indexes will always return null. Arrays can be indexed into using array[index] syntax (e.g. attachments[0] for the first attachment).
{
"attachments": [
{"file_type": "html"},
{"file_type": "pdf"},
{"file_type": "png"}
]
}Array indexing uses array[index] syntax:
attachments[0].file_type -> [{"file_type": "html"}]
attachments[0].file_type -> "html"
attachments[1].file_type -> "pdf"
attachments[10].file_type -> null
attachments[-1].file_type -> nullArray indexing uses array[start:end] , array[start:], array[:end] syntax. Out of bounds accesses on an array are clamped to the beginning and end of the array, and null array indexes return null.
attachments[:2] -> [{"file_type": "html"}, {"file_type": "pdf"}]
attachments[1:] -> [{"file_type": "pdf"}, {"file_type": "png"}]
attachments[1:2] -> [{"file_type": "pdf"}]
attachments[:10] -> [{"file_type": "html"}, {"file_type": "pdf"}, {"file_type": "png"}]
attachments[100:200] -> []Array construction
Create arrays on-the-fly with a list of literal or dynamic values. Arrays can be combined with array functions such as any and all to consolidate logic.
To create an array, encapsulate a list of values in [ ]
["foo", "bar", "baz"]
[body.plain.text, body.html.text]For example, to check if either body.plain.text or body.html.text contain a Social Security Number:
any([body.plain.text, body.html.text],
regex.contains(., '\b(\d\d\d)-(\d\d)-(\d\d\d\d)\b')
)Using any with an custom array is equivalent to writing an or with two regex.contains calls:
regex.contains(body.plain.text, '\b(\d\d\d)-(\d\d)-(\d\d\d\d)\b') or
regex.contains(body.html.text, '\b(\d\d\d)-(\d\d)-(\d\d\d\d)\b')To check if any of the recipients is a disposable email provider:
any([recipients.to, recipients.cc, recipients.bcc],
any(., .email.domain.domain in $disposable_email_providers)
)See array functions for the full list of array functions.
JSON type
To parse a JSON string to the JSON type, see strings.parse_json.
In addition to recognizing the specific schema for the Message Data Model and functions, MQL can traverse an arbitrary, schemaless JSON document. Because the schema isn't defined, the syntax to retrieve keys is different than it is from fields on the MDM.
JSON objects build a hierarchy. Traversing a JSON type in MQL results in intermediate JSON typed values which can be used by any other part of MQL. The JSON hierachy is:
{string: JSON}booleanstringfloat[JSON]
For example, if there was a JSON object in a field .json that looks like:
{
"company": "Sublime Security",
"$url": "https://sublime.security",
"meta": {
"name": "Sublime Security · The new standard for email security",
"description": "Sublime is an adaptive email security platform that combines best-in-class effectiveness with unprecedented visibility and control.",
"image": "https://cdn.prod.website-files.com/6734d4696c8f76142b33121b/6759b520893a25f4c27f5024_OG_Image.png"
},
"is_responsive": true,
"nav": [
"Solutions",
"Platform",
"About Us",
"Blog"
]
}JSON can be traversed in MQL with [<key>] syntax to access a key:
.json["company"]
// "Sublime Security"To compare JSON, use it freely with any normal operators:
.json["company"] == "Sublime Security"Or pass JSON data into functions, where the types are already matched
strings.ilike(.json["$url"], "https://*.security")Iterating arrays is also possible with array functions:
any(.json["nav"], . == "Solutions")Iterating the keys and values of JSON map objects is also possible with map functions :
any(keys(.json["meta"]), . == "name")any(values(.json["meta"]), . == "Sublime Security · The new standard for email security")However, interpreting a JSON as a boolean needs to be explicit. This is to make it more clear and readable that in MQL, boolean logic is exact and doesn't operate on "truthy" values (e.g. in Python, [] can be interpreted as false in boolean logic).
// Not allowed in MQL
not .json["is_responsive"]
// Explicit boolean logic is required for JSON types
.json["is_responsive"] == true
.json["is_responsive"] == false
not .json["is_responsive"]
.json["company"] == "Sublime Security"Because JSON has a dynamic type, mismatching types will result in a null result:
// Mismatched type, results in `null`
.json["company"] == 100
.json["company"] == .json["nav"]Updated about 23 hours ago