7.6. DATA

The DATA context is executed once for every recipient when the message is fully received (but not yet accepted). If multiple types of actions are performed, the response message (sent back to the client) will be choosen in the order of Reject, Defer, Quarantine, Delete, Deliver.

7.6.1. Pre-defined variables

These are the read-only pre-defined variables available for each recipient (on a message).

7.6.1.1. Connection

Variable Type Example Description
$senderip string “192.168.1.11” IP address of the connected client
$senderport number 41666 TCP port of connected client
$serverip string “10.0.0.1” IP address of the mailserver
$serverport number 25 TCP port of the mailserver
$serverid string “mailserver:1” ID of the mailserver profile
$senderhelo string “mail.example.com” HELO message of sender
$tlsstarted boolean false Whether or not the SMTP session is using TLS
$saslauthed boolean true Whether or not the SMTP session is authenticated (SASL)
$saslusername string “mailuser” SASL username

These are the writable pre-defined variables available.

Variable Type Description
$context any Connection-bound variable

7.6.1.2. Transaction

Variable Type Example Description
$messageid string “18c190a3-93f-47d7-bd...” ID of the message
$senderdomain string “example.org” Domain part of sender’s address (envelope)
$sender string “test@example.org” E-mail address of sender (envelope)
$senderparams array [“SIZE” => “2048”, ... ] Sender parameters to the envelope address
$recipientdomains array [“example.com”, ...] List of all domain part of all recipient addresses (envelope)
$recipients array [“test@example.com”, ...] List of all recipient addresses (envelope), in order of scanning

7.6.1.3. Arguments

Variable Type Example Description
$recipientdomain string “example.com” Domain part of recipient’s address (envelope)
$recipient string “test@example.com” E-mail address of recipient (envelope)
$transportid string “mailtransport:1” ID of the transport profile to be used
$actionid number 1 ID; incremented per message action/recipient (Deliver, Quarantine, etc.)

7.6.2. Functions

7.6.2.1. Misc

data.GetAddressList(value)

Extract addresses from a header value, often used with From, To and CC headers.

Parameters:value (string) – value to extract e-mail addresses from
Returns:e-mail addresses
Return type:array
$headerSender = GetAddressList(GetHeader("From"))[0]; // first e-mail address in From header
data.GetMailQueueMetric(options)

Return metric information about the mail queue, it can be used to enforce quotas.

Parameters:options (array) – options array
Return type:number

The following options are available in the options array.

  • metric (string) Metric to be returned; count or bytes. The default is count.
  • filter (array) Any of the available filters, see below. The default is no filters.

The following filters are available in the filters array.

Type Example
senderip $senderip
saslusername $saslusername
sender $sender
senderdomain $senderdomain
recipient $recipient
recipientdomain $recipientdomain
transportid $transportid
retry 1
$queuesize = GetMailQueueMetric(
        [
                "metric" => "bytes",
                "filter" => [
                        "senderdomain" => ["example.com" , "example.net"],
                        "transportid" => "mailtransport:2"
                ]
        ]
) / 1024 / 1024;
if ($queuesize > 500) {
        Defer("Current queue for mailtransport:2 exceeds 500 MiB");
}

Note

If multiple filters of the same type are given using array notation, any of them may match.

data.GetTLS([options])

Get the TLS information for a connection.

Parameters:options (array) – options array
Return type:array

The following options are available in the options array.

  • fingerprint (string) Generate the fingerprint of the certificate using one of the following hash function (md5, sha1, sha256 or sha512). The default no hashing.

The following items are available in the result.

  • started (boolean) If STARTTLS was issued.
  • protocol (string) The protocol used (eg. TLSv1.2)
  • ciphers (string) The cipher used (eg. ECDHE-RSA-AES256-SHA384).
  • keysize (number) The keysize used (eg. 256).
  • peer_cert (array) The peer certificate (if provided by the client). Same format as TLSSocket.getpeercert().
  • peer_cert_error (number) The peer certificate validation error (see OpenSSLs SSL_get_verify_result(3)).

7.6.2.2. Routing

data.SetSender(sender)

Change the sender of the message.

Parameters:sender (string) – an e-mail address
Returns:sender if successful
Return type:string or none
Updates:$sender and $senderdomain

Warning

This function changes the sender for all recipients. To change sender per recipient use SetSender() in the Pre-delivery context.

data.SetRecipient(recipient)

Changes the recipient.

Parameters:recipient (string) – an e-mail address
Returns:recipient if successful
Return type:string or none
Updates:$recipient and $recipientdomain
data.SetMailTransport(transportid)

Changes the transport profile.

Parameters:transportid (string) – the transportid to be used
Return type:none
Updates:$transportid
data.SetDelayedDeliver(delay)

If the message is queued, the first delivery attempt is delayed.

Parameters:delay (number) – delay in seconds
Return type:none
data.SetMetaData(metadata)

Set the metadata for the next recipient(s). The metadata must be an array with both string keys and values.

Parameters:metadata (array) – metadata to set
Return type:none
SetMetaData(["foo" => "bar", "foo2" => json_encode(["array", 123.45, false]));

Note

To work-around the data type limitation of the metadata; data can be encoded using json_encode().

data.GetMetaData()

Get the metadata set by SetMetaData(). If no data was set, an empty array is returned.

Returns:the data set by SetMetaData()
Return type:array
data.SetSenderIP(ip)

Change the senders IP of the message.

Parameters:ip (string) – an IP address
Returns:ip if successful
Return type:string or none
Updates:$senderip

Note

This function changes the $senderip for all recipients.

data.SetSenderHELO(hostname)

Change the senders HELO hostname of the message.

Parameters:hostname (string) – a hostname
Returns:hostname if successful
Return type:string or none
Updates:$senderhelo

Note

This function changes the $senderhelo for all recipients.

7.6.2.3. Headers

data.GetHeader(name[, decode = true])

Return the value of a header (if multiple headers with the same name exists, the first will be returned). The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • decode (boolean) – if false, the header will not be decoded
Returns:

header value

Return type:

string

data.GetHeaders(name[, decode = true])

Return the value of all headers with the name. If name is boolean true, all headers will be returned. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • decode (boolean) – if false, the header will not be decoded
Returns:

headers’ values

Return type:

array

data.AddHeader(name, value[, refold = true])

Add a new header (at the top of the message).

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • refold (boolean) – refold header to 80 characters per line
Return type:

none

data.SetHeader(name, value[, refold = true])

Overwrite existing header(s) or create a new header. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • refold (boolean) – refold header to 80 characters per line
Returns:

number of headers changed

Return type:

number

data.PrependHeader(name, value[, refold = true])

Prepend to existing header(s) or create a new header. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • refold (boolean) – refold header to 80 characters per line
Returns:

number of headers changed

Return type:

number

data.AppendHeader(name, value[, refold = true])

Append to existing header(s) or create a new header. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • refold (boolean) – refold header to 80 characters per line
Returns:

number of headers changed

Return type:

number

data.DelHeader(name)

Delete all headers by the name. The name is not case sensitive.

Parameters:name (string) – name of the header
Returns:number of headers deleted
Return type:number
data.GetRoute([extended_result = false])
Parameters:extended_result (boolean) – include more information
Returns:the message’s Received header(s) parsed in a usable format
Return type:array
data.GetDSN()

Parse a DSN message.

Returns:information about a DSN message
Return type:array or false
data.GetDSNHeader(name[, skip_decode = false])

Same as GetHeader except it works on attached DSN messages. The name is not case sensitive.

Parameters:
  • name (string) – the header
  • skip_decode (boolean) – if decoding should be skipped (return raw)
Returns:

the header value

Return type:

string

7.6.2.4. Actions

data.Deliver([options])

Deliver the message.

Parameters:options (array) – an options array
Returns:doesn’t return, script is terminated
Updates:$actionid

The following options are available in the options array.

  • recipient (string) set the recipient. The default is $recipient.
  • transportid (string) set the transportid. The default is $transportid.
  • metadata (array) add additional metadata to the message (KVP). same as SetMetaData().
  • delay (number) same as SetDelayedDeliver(). The default is 0 seconds.
  • done (boolean) if the function should terminate the script. Same as calling Done(). The default is true.
  • queue (boolean) deliver the message using the delivery queue. The default is true.
  • disconnect (boolean) disconnect the client. The default is false.
  • reply_codes (array) The array may contain code (number) and enhanced (array of three numbers). The default is pre-defined.
data.Reject([reason[, options]])

Reject (550) a message. If reason is an array or contains \n it will be split into a multiline response.

Parameters:
  • reason (string or array) – reject message with reason
  • options (array) – an options array
Returns:

doesn’t return, script is terminated

Updates:

$actionid

The following options are available in the options array.

  • disconnect (boolean) disconnect the client. The default is false.
  • reply_codes (array) The array may contain code (number) and enhanced (array of three numbers). The default is pre-defined.
data.Defer([reason[, options]])

Defer (421) a message. If reason is an array or contains \n it will be split into a multiline response.

Parameters:
  • reason (string or array) – reject message with reason
  • options (array) – an options array
Returns:

doesn’t return, script is terminated

Updates:

$actionid

The following options are available in the options array.

  • disconnect (boolean) disconnect the client. The default is false.
  • reply_codes (array) The array may contain code (number) and enhanced (array of three numbers). The default is pre-defined.
data.Delete()

Delete the message (and return 250).

Returns:doesn’t return, script is terminated
Updates:$actionid
data.Quarantine(quarantineid[, options])

Quarantine or archive a message.

Parameters:
  • quarantineid (string) – the quarantine profile
  • options (array) – an options array
Returns:

doesn’t return, script is terminated

Updates:

$actionid

The following options are available in the options array.

  • recipient (string) set the recipient. The default is $recipient.
  • transportid (string) set the transportid. The default is $transportid.
  • metadata (array) add additional metadata to the message (KVP). same as SetMetaData().
  • done (boolean) if the function should terminate the script. Same as calling Done(). The default is true.
  • reject (boolean) if the function should return an 500 error. The default is true.
  • reason (string) the reason to report. The default is a system generated message.
  • reply_codes (array) The array may contain code (number) and enhanced (array of three numbers). The default is pre-defined.
data.DiscardMailDataChanges()

Discard any content changes to the message.

Returns:number of changes discarded
Return type:number
data.Done()

Finishes the execution of the current recipient without doing an additional action. If a message is scanned without any action, it will be deferred.

Returns:doesn’t return, script is terminated

7.6.2.5. Anti-spam and anti-virus

data.ScanRPD([options])

Scan the message using CYREN; anti-spam (RPD and LocalView) and zero-hour malware detection (VOD). It runs in either inbound or outbound mode, and it’s important to configure this correctly with the outbound option.

Parameters:options (array) – options array
Returns:score or refid
Return type:number, string or array

The following options are available in the options array.

  • refid (boolean) Return RefID (used to report FN and FP). The default is false.
  • outbound (boolean) Use RPD in outbound mode. The default is false.
  • extended_result (boolean) Return extended results. The default is false.

The following results are available in the extended results array.

  • refid (string) The refid
  • rules (array) The LocalView spam rules matched
  • spam_score (number) The spam score
  • spam_class (string) The spam class
  • virus_score (number) The virus score
  • virus_class (string) The virus class

On error the following items are available.

  • error (boolean) Indicates if there was an error during the scanning

RPD’s anti-spam classification scores and class names

Score Class Description
0 non-spam, unknown Unknown
10 suspect Suspect
40 valid-bulk Valid bulk
50 bulk Bulk
100 spam Spam

RPD’s anti-virus classification scores and class names

Score Class Description
0 non-virus, unkown Unknown
50 medium Medium probability
100 virus, high High probability
data.ScanSA([options])

Scan the message using SpamAssassin.

Parameters:options (array) – options array
Returns:score or rules
Return type:number or array

The following options are available in the options array.

  • rules (boolean) Return rules in an associative array with scores. The default is false.
  • extended_result (boolean) Return extended results. The default is false.

The following results are available in the extended results array.

  • rules (array) The rules matched

On error the following items are available.

  • error (boolean) Indicates if there was an error during the scanning
Builtin rules Score Description
NOT_SCANNED_TOO_BIG 0 Message was to big too big to be scanned
NOT_SCANNED_QUEUE_TOO_LONG 0 Queue was too long to SpamAssassin

A score of 5 or higher is what most people accept to be considered spam.

data.ScanKAV([options])

Scan the message using the commercial anti-virus.

Parameters:options (array) – options array
Returns:any viruses found
Return type:array

The following options are available in the options array.

  • extended_result (boolean) Return extended results. The default is false.

The following results are available in the extended results array.

  • rules (array) The rules matched

On error the following items are available.

  • error (boolean) Indicates if there was an error during the scanning
data.ScanCLAM([options])

Scan the message using CLAM anti-virus.

Parameters:options (array) – options array
Returns:any viruses found
Return type:array

The following options are available in the options array.

  • extended_result (boolean) Return extended results. The default is false.

The following results are available in the extended results array.

  • rules (array) The rules matched

On error the following items are available.

  • error (boolean) Indicates if there was an error during the scanning
data.ScanDLP([patterns[, options]])

Scan a message using the builtin DLP engine.

Parameters:
  • patterns (array) – array of pre-configured rules or an array of custom rules
  • options (array) – options array
Returns:

all patterns found (may include ERR_ rules even if not explicitly given in the patterns argument)

Return type:

array

The following options are available in the options array.

  • stop_on_match (boolean) processing the mail when one match (of the requested type) is found. The default is false.
  • timeout (number) set an approximate timeout time in seconds. The default in no timeout.
  • recursion_limit (number) how deep to dig through MIME trees, archive files (such as ZIP), etc. The default is 9.
  • partid (boolean) return a data structure with the partid where the pattern is found. The default is false.
  • extended_result (boolean) Return extended results. The default is false.

The following results are available in the extended results array.

  • rules (array) The rules matched

On error the following items are available.

  • error (boolean) Indicates if there was an error during the scanning

The patterns array may either be an array of pre-configured rules by name.

["RULE1", "RULE2", ...]

Or a custom rule with the patterns provided. A custom rule may contain multiple types (eg. filename, sha1hash etc.) with multiple patterns each. The available types may be extracted from the DLP configuration.

["RULE1" => ["filename" => ["/\\.exe$/i", "/\\.zip$/i"], "sha1hash" => ["..."]], ...]

Warning

Do not allow untrusted users to add custom regular expression, since not all regular expressions are safe. All user data should be escaped using pcre_quote() before compiled into a regular expression.

There are some builtin rules which may occur.

Builtin rules Description
ERR_UNKNOWN_ERROR An unknown error occurred (more details may be available in the log)
ERR_PASSWORD_PROTECTED The archive is password protected
ERR_RECURSION_LIMIT The archive is too nested

7.6.2.6. DKIM

data.ScanDMARC()

Returns the DMARC policy to apply to the message for the From-address. It will return an associative array containing the domain as result. If the domain cannot be properly extracted or missing an error message will be returned.

Returns:associative array containing the domain and result or an error.
Return type:array or string
“permerror” An unknown error occurred (more details may be available in the log)
[“example.com” => “temperror”] A temporary error occurred (but the domain was known)
[“example.com” => “policy_absent”] No DMARC policy for domain
[“example.com” => “pass”] The DMARC passed
[“example.com” => “none”] The policy resulted in none
[“example.com” => “reject”] The policy resulted in reject
[“example.com” => “quarantine”] The policy resulted in quarantine
data.DKIMSign(selector, domain, key[, options])

Sign the message using DKIM.

Parameters:
  • selector (string) – selector to use when signing
  • domain (string) – domain to use when signing
  • key (string) – private key to use, either pki:X or a private RSA key in PEM format.
  • options (array) – options array
Returns:

true if the message could be signed

Return type:

boolean

The following options are available in the options array.

  • canonicalization_header (string) body canonicalization (simple or relaxed). The default is relaxed.
  • canonicalization_body (string) body canonicalization (simple or relaxed). The default is relaxed.
  • algorithm (string) algorithm to hash the message with (rsa-sha1,``rsa-sha256`` or ed25519-sha256). The default is rsa-sha256.
  • additional_headers (array) additional headers to sign in addition to those recommended by the RFC.
  • oversign_headers (array) headers to oversign. The default is from.
  • headers (array) headers to sign. The default is to sign all headers recommended by the RFC.
  • discard_changes (boolean) Discard any changes to the original message before signing. The default is false.
  • return_header (boolean) Return the DKIM signature as a string, instead of adding it to the message. The default is false.
  • arc (boolean) Create an ARC-Message-Signature header. The default is false.

Note

If return_header is used, you need to add the header yourself without refolding.

$dkimsig = DKIMSign("selector", "example.com", $key, ["return_header" => true]);
AddHeader("DKIM-Signature", $dkimsig, false); // without refolding
data.DKIMVerify(headerfield, [options]])

DKIM verify a DKIM-Signature or ARC-Message-Signature header. The header should include both the header name and value (unmodified).

Parameters:
  • headerfield (string) – the header to verify
  • options (array) – options array
Returns:

associative array containing the result.

Return type:

array

The following options are available in the options array.

  • timeout (number) the timeout (per DNS query). The default is 5.
  • dns_function (function) a custom DNS function. The default is to use the built in.

The DNS function will be called with the hostname (eg. 2018._domainkeys.example.com) for which a DKIM record should be returned. The result must be an array contaning either an error field (permerror or temperror) or a result field with a DKIM TXT record as string.

The resulting array always contains a result field of either pass, permerror or temperror. In case of an error the reason is included in an error field. If the header was successfully parsed (regardless of the result) a tags field will be included.

data.DKIMSDID([explicitdomains[, options]])

Returns the SDID (Signing Domain IDentifier) status from the DKIM header of the message.

Parameters:
  • explicitdomains (array) – array of explicit domains to check, empty array for all
  • options (array) – options array
Returns:

associative array containing the domain and result.

Return type:

array

The following options are available in the options array.

  • signature_limit (number) signatures to verify. The default is 5.
  • timeout (number) the timeout (per DNS query). The default is 5.
  • dns_function (function) a custom DNS function. The default is to use the built in.

The DNS function will be called with the hostname (eg. 2018._domainkeys.example.com) for which a DKIM record should be returned. The result must be an array contaning either an error field (permerror or temperror) or a result field with a DKIM TXT record as string.

Result Description
skip The validation of the DKIM record was not checked (due to the domain filter or signature limit)
pass The message was signed and the signature(s) passed verification.
fail The message was signed but they failed the verification.
temperror A later attempt may produce a final result.
permerror A later attempt is unlikely to produce a final result.

7.6.2.7. MIME and attachments

data.GetMailFile()

Return a File class to the current mail file.

Returns:A File class to the current mail file.
Return type:File

Note

The file is returned in an unmodified state as received (only with a Received header applied).

class data.MIME(partid)
Parameters:partid (string) – the part id

Working with MIME parts is done using MIME objects. To instantiate a reference to the root MIME part object call the MIME function with the string literal “0” (zero) as the argument.

Warning

If you call the MIME function without arguments (partid), the standard library’s MIME object will be created instead.

MIME("0")->appendPart(
        MIME()
                ->setType("multipart/alternative")
                ->appendPart(
                        MIME()
                                ->setType("text/plain")
                                ->setBody("This is a custom footer")
                        )
                ->appendPart(
                        MIME()
                                ->setType("multipart/related")
                                ->appendPart(
                                        MIME()
                                                ->setType("text/html")
                                                ->setBody("This is a custom footer with an image <img src='cid:logo.png'>")
                                )
                                ->appendPart(
                                        MIME()
                                                ->setType("image/png")
                                                ->addHeader("Content-ID", "logo.png")
                                                ->setBody(
                                                        cache [ "ttl" => 3600 * 24 * 7 ]
                                                                http("https://pbs.twimg.com/profile_images/656816032930119680/52m1eugJ.jpg")
                                                )
                                )
                        )
);

Note

Changes done to any MIME object will not be reflected on consecutive calls to “get” functions, however they will be applied to the message upon delivery.

getID()

Return the MIME part’s ID. This ID can be used to instantiate a new MIME object.

Returns:part id
Return type:string
mime.getSize()

return the mime part’s size in bytes.

Returns:size in bytes
Return type:number
getFileName()

Return the MIME part’s file name (if it has one).

Returns:file name
Return type:string (or none)
getType()

Return the MIME part’s Content-Type‘s type field (eg. text/plain).

Returns:content type
Return type:string (or none)
getHeader(name[, options])

Return the value of a header (if multiple headers with the same name exists, the first will be returned). If no header is found, the type none is returned. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • options (array) – an options array
Returns:

header value

Return type:

string (or none)

The following options are available in the options array.

  • index (number) The index of the header, from the top, starting at zero. The default is 0.
  • field (boolean) Get the header field as is (including the name). The default is false.
if (is_string($contentid = $part->getHeader("Content-ID")))
        echo "Content-ID is $contentid";

Note

The getHeader function family will return headers as a UTF-8 string with all MIME encoded-words decoded (=?charset?encoding?data?=). However even if headers must be in 7-bit ASCII, some senders do not conform to this and do send headers with different charset encodings. In those cases we (1) Use the MIME-parts “Content-Type” headers charset when converting to UTF-8. (2) If there is no charset information available we use a statistical charset detection function. (3) We just pretend it to be US-ASCII and covert it to UTF-8 anyway (guaranteeing the result will be valid UTF-8).

getHeaders(name[, options])

Return a list of header values. If no header is found, an empty list is returned. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • options (array) – an options array
Returns:

header values

Return type:

array of string

The following options are available in the options array.

  • field (boolean) Get the header field as is (including the name). The default is false.
echo "Received headers: ".count(MIME("0")->getHeaders("Received"));
getHeaderNames()

Return a list of all header names, from the top. The names are in lower case.

Returns:header names
Return type:array of string
setHeader(name, value[, options])

Overwrite existing header(s) or create a new header. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • options (array) – an options array
Returns:

number of headers changed

Return type:

number

The following options are available in the options array.

  • index (number) The index of the header, from the top, starting at zero.
  • encode (number) Refold and encode the header. The default is true.
addHeader(name, value[, options])

Add a new header (at the top of the message).

Parameters:
  • name (string) – name of the header
  • value (string) – value of the header
  • options (array) – an options array
Return type:

none

The following options are available in the options array.

  • encode (number) Refold and encode the header. The default is true.
delHeader(name[, options])

Delete all headers by the name. The name is not case sensitive.

Parameters:
  • name (string) – name of the header
  • options (array) – an options array
Returns:

number of headers deleted

Return type:

number

The following options are available in the options array.

  • index (number) The index of the header, from the top, starting at zero.
remove()

Remove this MIME part.

Return type:none
getBody()

Get the body (content) of a MIME part. The content will be decoded according to the Content-Transfer-Encoding header. If the body size is bigger than 1 MiB, the type none is returned.

Returns:the body content
Return type:string (or none)

Note

The getBody function will decode using the “Content-Transfer-Encoding” header. It will not do any character set encoding, hence the data can be in any character set encoding.

setBody(data)

Set the body (content) of a MIME part. If the body argument is bigger than 1 MiB (or an another error occured), the type none is returned. The MIME parts encoding (Content-Transfer-Encoding) will be changed to base64 as the data will encoded as such.

Parameters:data (string) – the body content
Returns:this
Return type:MIME (or none)
prependPart(part)

Add a MIME part before this part.

Parameters:part (MIME) – a MIME part
Returns:this
Return type:MIME
appendPart(part)

Add a MIME part after this part.

Parameters:part (MIME) – a MIME part
Returns:this
Return type:MIME
replacePart(part)

Replace the current MIME part.

Parameters:part (MIME) – a MIME part
Return type:none
findByType(type)

Find descendant parts (on any depth) based on their Content-Type.

Parameters:type (string) – type as regex
Returns:parts
Return type:array of MIME objects
findByFileName(filename)

Find descendant parts (on any depth) based on their file name.

Parameters:filename (string) – filename as regex
Returns:parts
Return type:array of MIME objects
getParts()

Return child parts.

Returns:parts
Return type:array of MIME objects

7.6.3. On script error

On script error Defer() is called.

7.6.4. On implicit termination

If not explicitly terminated then Deliver() is called.