7.6.1. Per message¶
The per-message end-of-DATA script is executed once, when the message is fully received (but not yet accepted).
To relay the message for all recipients, call Queue()
for each $transaction["recipients"]
and then Accept()
.
7.6.1.1. Pre-defined variables¶
These are the read-only pre-defined variables available for each recipient (on a message).
7.6.1.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 server |
$serverport | number | 25 | TCP port of the server |
$serverid | string | “mailserver:1” | ID of the server |
$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.1.2. Transaction¶
Variable | Type | Example | Description |
---|---|---|---|
$transaction | array | [...] | Contains the transaction ID and envelope data (sender and recipient) |
The $transaction
variable is an array with
Array item | Type | Example | Description |
---|---|---|---|
“id” | string | “18c190a3-93f-47d7-bd...” | ID of the transaction |
“sender” | string | “test@example.org” | Email address of sender (envelope), lowercase |
“senderlocalpart” | string | “test” | Local part of sender’s address (envelope) |
“senderdomain” | string | “example.org” | Domain part of sender’s address (envelope) |
“senderparams” | array | [“SIZE” => “2048”, ... ] | Sender parameters to the envelope address |
“recipients” | array | [...] | List of all accepted recipients (envelope), in order of scanning |
where "recipients"
is an array with
Array item | Type | Example | Description |
---|---|---|---|
“recipient” | string | “test@example.com” | Recipient address, lowercase |
“recipientlocalpart” | string | “test” | Local part of recipient address |
“recipientdomain” | string | “example.com” | Domain part of recipient address |
“recipientparams” | array | [“NOTIFY” => “NEVER”, .. ] | Recipient parameters to the envelope address |
“transportid” | string | “mx” | Transport ID for recipient |
7.6.1.1.3. Arguments¶
The are no arguments to the per-message end-of-DATA script. The mail data file is however available via several functions.
7.6.1.2. Functions¶
- Actions
Accept()
Defer()
Reject()
- Queueing
Queue()
History()
- MIME and attachments
GetMailFile()
MIME
- DKIM
ScanDMARC()
DKIMSign()
DKIMVerify()
DKIMSDID()
- Embedded content scanning
ScanDLP()
ScanRPD()
ScanSA()
ScanKAV()
ScanCLAM()
- Miscellaneous
GetAddressList()
GetMailQueueMetric()
GetTLS()
7.6.1.2.1. Actions¶
-
Accept
()¶ Accept the DATA command (mail data).
Returns: doesn’t return, script is terminated
-
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) – defer message with reason
- options (array) – an options array
Returns: doesn’t return, script is terminated
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.
-
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
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.
7.6.1.2.2. Queueing¶
-
Queue
(recipient, transportid[, options])¶ Queue the message.
Parameters: - recipient (string or array) – the recipient email address, either as a string or a tuple with localpart and domain
- transportid (string) – the transport profile ID
- options (array) – an options array
Returns: true (or none)
Return type: boolean or none
The following options are available in the options array.
- sender (string) The sender email address, either as a string or a tuple with localpart and domain. The default is
$transaction["senderlocalpart"]
at$transaction["senderdomain"]
. - metadata (array) Add metadata to the queued message, as a key-value pair array of strings.
- hold (boolean) Put the message in the hold (inactive) queue.
- delay (number) Delay the first delivery attempt, in seconds. The default is
0
.
-
History
(action, recipient[, options])¶ Add an entry to the history database table. This function is only available in the full system distribution (virtual machine) package. For long-term logging in high volume systems, remote logging to an external database such as Elasticsearch is recommended.
Parameters: - action (string) – the logged action; either of REJECT, DELETE, DELIVER, DEFER or ERROR
- recipient (string or array) – the recipient email address, either as a string or a tuple with localpart and domain
- options (array) – an options array
Returns: true (or none)
Return type: boolean or none
The following options are available in the options array.
- sender (string) the sender email address, either as a string or a tuple with localpart and domain. The default is
$transaction["senderlocalpart"]
at$transaction["senderdomain"]
. - metadata (array) add metadata to the history entry, as a key-value pair array of strings
- transportid (string) the transport profile ID
- reason (string) reason message
7.6.1.2.3. MIME and attachments¶
-
GetMailFile
([options])¶ Return a
File
class to the current mail file.Parameters: options (array) – an options array Returns: A File class to the current mail file. Return type: File The following options are available in the options array.
- changes (boolean) Include changes done to the original message. The default is
false
.
- changes (boolean) Include changes done to the original message. The default is
-
class
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’sMIME
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.
-
reset
()¶ Undo all changes on the message. Only works on the root.
Returns: number of changes discarded Return type: number MIME("0")->reset();
-
snapshot
()¶ Take a snapshot of the current state of the MIME object (to be used with
MIME.restore()
). Only works on the root.Returns: snapshot id Return type: number $id = MIME("0")->snapshot();
-
restore
(id)¶ Restore to a snapshot (to be used with
MIME.snapshot()
). Only works on the root.Parameters: id (number) – snapshot id Returns: success Return type: boolean MIME("0")->restore($id);
-
getID
()¶ Return the MIME part’s ID. This ID can be used to instantiate a new
MIME
object.Returns: part id Return type: string
-
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 occurred), 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
partReturns: this Return type: MIME
-
appendPart
(part)¶ Add a MIME part after this part.
Parameters: part (MIME) – a MIME
partReturns: this Return type: MIME
-
replacePart
(part)¶ Replace the current MIME part.
Parameters: part (MIME) – a MIME
partReturn 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
-
7.6.1.2.4. DKIM¶
These are DKIM-related functions, including DMARC. Other modules, such as ARC, is available in the authentication script library.
-
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
-
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
orrelaxed
). The default isrelaxed
. - canonicalization_body (string) body canonicalization (
simple
orrelaxed
). The default isrelaxed
. - algorithm (string) algorithm to hash the message with (
rsa-sha1
,rsa-sha256
ored25519-sha256
). The default isrsa-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
-
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 containing either an
error
field (permerror
ortemperror
) or aresult
field with a DKIM TXT record as string.The resulting array always contains a
result
field of eitherpass
,permerror
ortemperror
. In case of an error the reason is included in anerror
field. If the header was successfully parsed (regardless of the result) atags
field will be included.
-
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 containing either an
error
field (permerror
ortemperror
) or aresult
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.1.2.5. Embedded content scanning¶
These functions scan the message file using various engines.
While the DLP engine dlpd
is included in all software packages, the embedded anti-spam and anti-virus engines are only available in the full system distribution (virtual machine) package.
All connectors are available in the script library.
-
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
-
ScanRPD
([options])¶ Scan the message using Cyren; anti-spam
ctasd
(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, unknown Unknown 50 medium Medium probability 100 virus, high High probability - refid (boolean) Return RefID (used to report FN and FP). The default is
-
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.
- rules (boolean) Return rules in an associative array with scores. The default is
-
ScanKAV
([options])¶ Scan the message using the Sophos 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
- extended_result (boolean) Return extended results. The default is
-
ScanCLAM
([options])¶ Scan the message using ClamAV 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
- extended_result (boolean) Return extended results. The default is
7.6.1.2.6. Miscellaneous¶
-
GetAddressList
(value)¶ Extract addresses from a header value, often used with From, To and CC headers.
Parameters: value (string) – value to extract email addresses from Returns: email addresses Return type: array $headerSender = GetAddressList(GetHeader("From"))[0]; // first email address in From header
-
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 metadata.x any metadata $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.
-
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
orsha512
). 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)).
- fingerprint (string) Generate the fingerprint of the certificate using one of the following hash function (