&` _DRIVER_ROUTER_* `& router drivers
&` _DRIVER_TRANSPORT_* `& transport drivers
&` _DRIVER_AUTHENTICATOR_* `& authenticator drivers
+&` _LOG_* `& log_selector values
&` _OPT_MAIN_* `& main config options
&` _OPT_ROUTERS_* `& generic router options
&` _OPT_TRANSPORTS_* `& generic transport options
.code
${length_<n>:<string>}
.endd
-The result of this item is either the first <&'n'&> characters or the whole
+The result of this item is either the first <&'n'&> bytes or the whole
of <&'string2'&>, whichever is the shorter. Do not confuse &%length%& with
&%strlen%&, which gives the length of a string.
+All measurement is done in bytes and is not UTF-8 aware.
.vitem "&*${listextract{*&<&'number'&>&*}&&&
yields &"K1=A K4=D K3=C"&. Note the use of &`\N`& to protect the contents of
the regular expression from string expansion.
+The regular expression is compiled in 8-bit mode, working against bytes
+rather than any Unicode-aware character handling.
.vitem &*${sort{*&<&'string'&>&*}{*&<&'comparator'&>&*}{*&<&'extractor'&>&*}}*&
If the starting offset is greater than the string length the result is the
null string; if the length plus starting offset is greater than the string
length, the result is the right-hand part of the string, starting from the
-given offset. The first character in the string has offset zero.
+given offset. The first byte (character) in the string has offset zero.
The &%substr%& expansion item can take negative offset values to count
-from the right-hand end of its operand. The last character is offset -1, the
-second-last is offset -2, and so on. Thus, for example,
+from the right-hand end of its operand. The last byte (character) is offset -1,
+the second-last is offset -2, and so on. Thus, for example,
.code
${substr{-5}{2}{1234567}}
.endd
yields &"1"&.
When the second number is omitted from &%substr%&, the remainder of the string
-is taken if the offset is positive. If it is negative, all characters in the
+is taken if the offset is positive. If it is negative, all bytes (characters) in the
string preceding the offset point are taken. For example, an offset of -1 and
no length, as in these semantically identical examples:
.code
.endd
yields all but the last character of the string, that is, &"abcd"&.
+All measurement is done in bytes and is not UTF-8 aware.
+
.vitem "&*${tr{*&<&'subject'&>&*}{*&<&'characters'&>&*}&&&
{*&<&'replacements'&>&*}}*&"
.cindex "expansion" "character translation"
.cindex "&%tr%& expansion item"
-This item does single-character translation on its subject string. The second
+This item does single-character (in bytes) translation on its subject string. The second
argument is a list of characters to be translated in the subject string. Each
matching character is replaced by the corresponding character from the
replacement list. For example
last occurrence is used. If the third string is shorter than the second, its
last character is replicated. However, if it is empty, no translation takes
place.
+
+All character handling is done in bytes and is not UTF-8 aware.
+
.endlist
header line, and the effective address is extracted from it. If the string does
not parse successfully, the result is empty.
+The parsing correctly handles SMTPUTF8 Unicode in the string.
+
.vitem &*${addresses:*&<&'string'&>&*}*&
.cindex "expansion" "RFC 2822 address handling"
example below is passed the contents of &`$header_from:`&, meaning it gets
de-mimed. Exim sees the decoded "," so it treats it as &*two*& email addresses.
The third example shows that the presence of a comma is skipped when it is
-quoted.
+quoted. The fourth example shows SMTPUTF8 handling.
.code
# exim -be '${addresses:From: \
=?iso-8859-2?Q?Last=2C_First?= <user@example.com>}'
Last:user@example.com
# exim -be '${addresses:From: "Last, First" <user@example.com>}'
user@example.com
+# exim -be '${addresses:フィル <フィリップ@example.jp>}'
+フィリップ@example.jp
.endd
.vitem &*${base32:*&<&'digits'&>&*}*&
.code
${lc:$local_part}
.endd
+Case is defined per the system C locale.
.vitem &*${length_*&<&'number'&>&*:*&<&'string'&>&*}*&
.cindex "expansion" "string truncation"
See the description of the general &%length%& item above for details. Note that
&%length%& is not the same as &%strlen%&. The abbreviation &%l%& can be used
when &%length%& is used as an operator.
+All measurement is done in bytes and is not UTF-8 aware.
.vitem &*${listcount:*&<&'string'&>&*}*&
The string is interpreted as an RFC 2822 address and the local part is
extracted from it. If the string does not parse successfully, the result is
empty.
+The parsing correctly handles SMTPUTF8 Unicode in the string.
.vitem &*${mask:*&<&'IP&~address'&>&*/*&<&'bit&~count'&>&*}*&
If you are creating a new email address from the contents of &$local_part$&
(or any other unknown data), you should always use this operator.
+This quoting determination is not SMTPUTF8-aware, thus quoting non-ASCII data
+will likely use the quoting form.
+Thus &'${quote_local_part:フィル}'& will always become &'"フィル"'&.
+
.vitem &*${quote_*&<&'lookup-type'&>&*:*&<&'string'&>&*}*&
.cindex "quoting" "lookup-specific"
.cindex "&%strlen%& expansion item"
The item is replace by the length of the expanded string, expressed as a
decimal number. &*Note*&: Do not confuse &%strlen%& with &%length%&.
+All measurement is done in bytes and is not UTF-8 aware.
.vitem &*${substr_*&<&'start'&>&*_*&<&'length'&>&*:*&<&'string'&>&*}*&
.endd
See the description of the general &%substr%& item above for details. The
abbreviation &%s%& can be used when &%substr%& is used as an operator.
+All measurement is done in bytes and is not UTF-8 aware.
.vitem &*${time_eval:*&<&'string'&>&*}*&
.cindex "&%time_eval%& expansion item"
.cindex "expansion" "case forcing"
.cindex "&%uc%& expansion item"
This forces the letters in the string into upper-case.
+Case is defined per the system C locale.
.vitem &*${utf8clean:*&<&'string'&>&*}*&
.cindex "correction of invalid utf-8 sequences in strings"
.cindex "expansion" "utf-8 forcing"
.cindex "&%utf8clean%& expansion item"
This replaces any invalid utf-8 sequence in the string by the character &`?`&.
+.new
+In versions of Exim before 4.92, this did not correctly do so for a truncated
+final codepoint's encoding, and the character would be silently dropped.
+If you must handle detection of this scenario across both sets of Exim behavior,
+the complexity will depend upon the task.
+For instance, to detect if the first character is multibyte and a 1-byte
+extraction can be successfully used as a path component (as is common for
+dividing up delivery folders), you might use:
+.code
+condition = ${if inlist{${utf8clean:${length_1:$local_part}}}{:?}{yes}{no}}
+.endd
+(which will false-positive if the first character of the local part is a
+literal question mark).
+.wen
.vitem "&*${utf8_domain_to_alabel:*&<&'string'&>&*}*&" &&&
"&*${utf8_domain_from_alabel:*&<&'string'&>&*}*&" &&&
.cindex "&%eqi%& expansion condition"
The two substrings are first expanded. The condition is true if the two
resulting strings are identical. For &%eq%& the comparison includes the case of
-letters, whereas for &%eqi%& the comparison is case-independent.
+letters, whereas for &%eqi%& the comparison is case-independent, where
+case is defined per the system C locale.
.vitem &*exists&~{*&<&'file&~name'&>&*}*&
.cindex "expansion" "file existence test"
string is lexically greater than or equal to the second string. For &%ge%& the
comparison includes the case of letters, whereas for &%gei%& the comparison is
case-independent.
+Case and collation order are defined per the system C locale.
.vitem &*gt&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*& &&&
&*gti&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
string is lexically greater than the second string. For &%gt%& the comparison
includes the case of letters, whereas for &%gti%& the comparison is
case-independent.
+Case and collation order are defined per the system C locale.
.vitem &*inlist&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*& &&&
&*inlisti&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
Both strings are expanded; the second string is treated as a list of simple
strings; if the first string is a member of the second, then the condition
is true.
+For the case-independent &%inlisti%& condition, case is defined per the system C locale.
These are simpler to use versions of the more powerful &*forany*& condition.
Examples, and the &*forany*& equivalents:
string is lexically less than or equal to the second string. For &%le%& the
comparison includes the case of letters, whereas for &%lei%& the comparison is
case-independent.
+Case and collation order are defined per the system C locale.
.vitem &*lt&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*& &&&
&*lti&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
string is lexically less than the second string. For &%lt%& the comparison
includes the case of letters, whereas for &%lti%& the comparison is
case-independent.
+Case and collation order are defined per the system C locale.
.vitem &*match&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
and it may match anywhere in the subject, not just at the start. If you want
the pattern to match at the end of the subject, you must include the &`$`&
metacharacter at an appropriate point.
+All character handling is done in bytes and is not UTF-8 aware,
+but we might change this in a future Exim release.
.cindex "numerical variables (&$1$& &$2$& etc)" "in &%if%& expansion"
At the start of an &%if%& expansion the values of the numeric variable
&`F `& sender address (on delivery lines)
&`H `& host name and IP address
&`I `& local interface used
-&`K `& CHUNKING extension used
&`id `& message id for incoming message
+&`K `& CHUNKING extension used
+&`L `& on &`<=`& and &`=>`& lines: PIPELINING extension used
&`M8S `& 8BITMIME status for incoming message
&`P `& on &`<=`& lines: protocol used
&` `& on &`=>`& and &`**`& lines: return path
&` queue_time `& time on queue for one recipient
&` queue_time_overall `& time on queue for whole message
&` pid `& Exim process id
+&` pipelining `& PIPELINING use, on <= and => lines
&` proxy `& proxy address on <= and => lines
&` receive_time `& time taken to receive message
&` received_recipients `& recipients on <= lines
&%pid%&: The current process id is added to every log line, in square brackets,
immediately after the time and date.
.next
+.new
+.cindex log pipelining
+.cindex pipelining "logging outgoing"
+&%pipelining%&: A field is added to delivery and accept
+log lines when the ESMTP PIPELINING extension was used.
+The field is a single "L".
+On accept lines, where PIPELINING was offered but not used by the client,
+the field has a minus appended.
+.next
.cindex "log" "queue run"
.cindex "queue runner" "logging"
&%queue_run%&: The start and end of every queue run are logged.
is insurance against disk crashes where the directory is lost but the files
themselves are recoverable.
+.new
+The file formats may be changed, or new formats added, at any release.
+Spool files are not intended as an interface to other programs
+and should not be used as such.
+.wen
+
Some people are tempted into editing -D files in order to modify messages. You
need to be extremely careful if you do this; it is not recommended and you are
on your own if you do it. Here are some of the pitfalls: