+ a delay in an ACL. It also flushes the output before performing a callout,
+ as this can take a substantial time. These behaviours can be disabled by
+ obeying control = no_delay_flush or control = no_callout_flush,
+ respectively, at some earlier stage of the connection. The effect of the
+ new default behaviour is to disable the PIPELINING optimization in these
+ situations, in order to avoid unexpected timeouts in clients.
+
+12. There are two new expansion conditions that iterate over a list. They are
+ called forany and forall, and they are used like this:
+
+ ${if forany{<a list>}{<a condition>}{<yes-string>}{<no-string>}}
+ ${if forall{<a list>}{<a condition>}{<yes-string>}{<no-string>}}
+
+ The first argument is expanded, and the result is treated as a list. By
+ default, the list separator is a colon, but it can be changed by the normal
+ method. The second argument is interpreted as a condition that is to be
+ applied to each item in the list in turn. During the interpretation of the
+ condition, the current list item is placed in a variable called $item.
+
+ - For forany, interpretation stops if the condition is true for any item,
+ and the yes-string is then expanded. If the condition is false for all
+ items in the list, the no-string is expanded.
+
+ - For forall, interpration stops if the condition is false for any item,
+ and the no-string is then expanded. If the condition is true for all
+ items in the list, the yes-string is expanded.
+
+ Note that negation of forany means that the condition must be false for all
+ items for the overall condition to succeed, and negation of forall means
+ that the condition must be false for at least one item.
+
+ In this example, the list separator is changed to a comma:
+
+ ${if forany{<, $recipients}{match{$item}{^user3@}}{yes}{no}}
+
+ Outside a forany/forall condition, the value of $item is an empty string.
+ Its value is saved and restored while forany/forall is being processed, to
+ enable these expansion items to be nested.
+
+13. There's a new global option called dsn_from that can be used to vary the
+ contents of From: lines in bounces and other automatically generated
+ messages ("delivery status notifications" - hence the name of the option).
+ The default setting is:
+
+ dsn_from = Mail Delivery System <Mailer-Daemon@$qualify_domain>
+
+ The value is expanded every time it is needed. If the expansion fails, a
+ panic is logged, and the default setting is used.
+
+14. The smtp transport has a new option called hosts_avoid_pipelining. It can
+ be used to suppress the use of PIPELINING to certain hosts, while still
+ supporting the other SMTP extensions (cf hosts_avoid_tls).
+
+15. By default, exigrep does case-insensitive matches. There is now a -I option
+ that makes it case-sensitive. This may give a performance improvement when
+ searching large log files. Without -I, the Perl pattern matches use the /i
+ option; with -I they don't. In both cases it is possible to change the case
+ sensitivity within the pattern using (?i) or (?-i).
+
+16. A number of new features have been added to string expansions to make it
+ easier to process lists of items, typically addresses. These are as
+ follows:
+
+ * ${addresses:<string>}
+
+ The string (after expansion) is interpreted as a list of addresses in RFC
+ 2822 format, such as can be found in a To: or Cc: header line. The
+ operative address (local-part@domain) is extracted from each item, and the
+ result of the expansion is a colon-separated list, with appropriate
+ doubling of colons should any happen to be present in the email addresses.
+ Syntactically invalid RFC2822 address items are omitted from the output.
+
+ It is possible to specify a character other than colon for the output
+ separator by starting the string with > followed by the new separator
+ character. For example:
+
+ ${addresses:>& The Boss <ceo@up.stairs>, sec@base.ment (dogsbody)}
+
+ expands to "ceo@up.stairs&sec@base.ment". Compare ${address (singular),
+ which extracts the working address from a single RFC2822 address.
+
+ * ${map{<string1>}{<string2>}}
+
+ After expansion, <string1> is interpreted as a list, colon-separated by
+ default, but the separator can be changed in the usual way. For each item
+ in this list, its value is place in $item, and then <string2> is expanded
+ and added to the output as an item in a new list. The separator used for
+ the output list is the same as the one used for the input, but is not
+ included in the output. For example:
+
+ ${map{a:b:c}{[$item]}} ${map{<- x-y-z}{($item)}}
+
+ expands to "[a]:[b]:[c] (x)-(y)-(z)". At the end of the expansion, the
+ value of $item is restored to what it was before.
+
+ * ${filter{<string1>}{<condition>}}
+
+ After expansion, <string1> is interpreted as a list, colon-separated by
+ default, but the separator can be changed in the usual way. For each item
+ in this list, its value is place in $item, and then the condition is
+ evaluated. If the condition is true, $item is added to the output as an
+ item in a new list; if the condition is false, the item is discarded. The
+ separator used for the output list is the same as the one used for the
+ input, but is not included in the output. For example:
+
+ ${filter{a:b:c}{!eq{$item}{b}}
+
+ yields "a:c". At the end of the expansion, the value of $item is restored
+ to what it was before.
+
+ * ${reduce{<string1>}{<string2>}{<string3>}}
+
+ The ${reduce expansion operation reduces a list to a single, scalar string.
+ After expansion, <string1> is interpreted as a list, colon-separated by
+ default, but the separator can be changed in the usual way. Then <string2>
+ is expanded and assigned to the $value variable. After this, each item in
+ the <string1> list is assigned to $item in turn, and <string3> is expanded
+ for each of them. The result of that expansion is assigned to $value before
+ the next iteration. When the end of the list is reached, the final value of
+ $value is added to the expansion string. The ${reduce expansion item can be
+ used in a number of ways. For example, to add up a list of numbers:
+
+ ${reduce {<, 1,2,3}{0}{${eval:$value+$item}}}
+
+ The result of that expansion would be "6". The maximum of a list of numbers
+ can be found:
+
+ ${reduce {3:0:9:4:6}{0}{${if >{$item}{$value}{$item}{$value}}}}
+
+ At the end of a ${reduce expansion, the values of $item and $value is
+ restored to what they were before.
+
+17. There's a new ACL modifier called "continue". It does nothing of itself,
+ and processing of the ACL always continues with the next condition or
+ modifier. It is provided so that the side effects of expanding its argument
+ can be used. Typically this would be for updating a database. It is really
+ just a syntactic tidiness, because the following two lines have the same
+ effect:
+
+ continue = <some expansion>
+ condition = ${if eq{0}{<some expansion>}{true}{true}}
+
+18. It is now possible to use newline and other control characters (those with
+ values less than 32, plus DEL) as separators in lists. Such separators must
+ be provided literally at the time the list is processed, but the string
+ expansion that happens first means that you can write them using normal
+ escape sequences. For example, if a new-line separated list of domains is
+ generated by a lookup, you can now process it directly by a line such as
+ this:
+
+ domains = <\n ${lookup mysql{.....}}
+
+ This avoids having to change the list separator in such data. Unlike
+ printing character separators, which can be included in list items by
+ doubling, it is not possible to include a control character as data when it
+ is set as the separator. Two such characters in succession are interpreted
+ as enclosing an empty list item.
+
+19. The exigrep utility now has a -v option, which inverts the matching
+ condition.
+
+20. The host_find_failed option in the manualroute router can now be set to
+ "ignore". This causes it to completely ignore a host whose IP address
+ cannot be found. If all the hosts in the list are ignored, the behaviour is
+ controlled by the new host_all_ignored option, which takes the same values
+ as host_find_failed, except that it cannot be set to "ignore". Its default
+ is "defer".