General-Purpose Mail Filter
Expressions are language constructs, that evaluate to a value, that can subsequently be echoed, tested in a conditional statement, assigned to a variable or passed to a function.
Literals and numbers are constant expressions. They evaluate to string and numeric types.
A function call is an expression. Its type is the return type of the function.
Concatenation operator is ‘.’ (a dot). For example, if
$f is ‘smith’, and
$f . "-" . $client_addr ⇒ "smith-10.10.1.1"
Any two adjacent literal strings are concatenated, producing a new string, e.g.
"GNU's" " not " "UNIX" ⇒ "GNU's not UNIX"
The filter script language offers the common arithmetic operators: ‘+’, ‘-’, ‘*’ and ‘/’. In addition, the ‘%’ is a modulo operator, i.e. it computes the remainder of division of its operands.
All of them follow usual precedence rules and work as you would expect them to.
The ‘<<’ represents a bitwise shift left operation, which shifts the binary representation of the operand on its left by the number of bits given by the operand on its right.
Similarly, the ‘>>’ represents a bitwise shift right.
Relational expressions are:
|x ||True if x is less than y.|
|x ||True if x is less than or equal to y.|
|x ||True if x is greater than y.|
|x ||True if x is greater than or equal to y.|
|x ||True if x is equal to y.|
|x ||True if x is not equal to y.|
The relational expressions apply to string as well as to numbers. When a relational operation applies to strings, case-sensitive comparison is used, e.g.:
"String" = "string" ⇒ False "String" < "string" ⇒ True
In addition to the traditional relational operators, described
mailfromd provides two operators for regular
|x ||True if the string x matches the regexp denoted by y.|
|x ||True if the string x matches the globbing pattern denoted by y.|
The type of the regular expression used by
is controlled by
#pragma regex (see pragma regex). For example:
$f ⇒ "firstname.lastname@example.org" $f matches '.*@gnu\.org\.ua' ⇒
true$f matches '.*@GNU\.ORG\.UA' ⇒
false#pragma regex +icase $f matches '.*@GNU\.ORG\.UA' ⇒
fnmatches operator compares its left-hand operand with a
globbing pattern (see glob(7)) given as its right-hand side
operand. For example:
$f ⇒ "email@example.com" $f fnmatches "*ua" ⇒
true$f fnmatches "*org" ⇒
false$f fnmatches "*org*" ⇒
Both operators have a special form, for ‘MX’ pattern matching. The expression:
x mx matches y
is evaluated as follows: first, the expression x is analyzed and, if it is an email address, its domain part is selected. If it is not, its value is used verbatim. Then the list of ‘MX’s for this domain is looked up. Each of ‘MX’ names is then compared with the regular expression y. If any of the names matches, the expression returns true. Otherwise, its result is false.
Similarly, the expression:
x mx fnmatches y
returns true only if any of the ‘MX’s for (domain or email) x match the globbing pattern y.
mx matches and
mx fnmatches can signal the
The value of any parenthesized subexpression occurring within the
right-hand side argument to
mx matches can be
referenced using the notation ‘\d’, where d is the
ordinal number of the subexpression (subexpressions are numbered from
left to right, starting at 1). This notation is allowed in the
program text as well as within double-quoted strings and
here-documents, for example:
if $f matches '.*@\(.*\)\.gnu\.org\.ua' set message "Your host name is \1;" fi
Remember that the grouping symbols are ‘\(’ and ‘\)’ for basic regular expressions, and ‘(’ and ‘)’ for extended regular expressions. Also make sure you properly escape all special characters (backslashes in particular) in double-quoted strings, or use single-quoted strings to avoid having to do so (see singe-vs-double, for a comparison of the two forms).
A boolean expression is a combination of relational or
matching expressions using the boolean operators
not, and, eventually, parentheses to control nesting:
|x ||True only if both x and y are true.|
|x ||True if any of x or y is true.|
|True if x is false.|
Binary boolean expressions are computed using shortcut evaluation:
x and y
x ⇒ , the result is
and y is not evaluated.
x or y
x ⇒ , the result is
y is not evaluated.
Operator precedence is an abstract value associated with each
language operator, that determines the order in which operators are
executed when they appear together within a single expression.
Operators with higher precedence are executed first. For example,
‘*’ has a higher precedence than ‘+’, therefore the
a + b * c is evaluated in the following order: first
b is multiplied by
a is added to the
When operators of equal precedence are used together they are evaluated from left to right (i.e., they are left-associative), except for comparison operators, which are non-associative (these are explicitly marked as such in the table below). This means that you cannot write:
if 5 <= x <= 10
Instead, you should write:
if 5 <= x and x <= 10
The precedences of the
mailfromd operators where selected
so as to match that used in most programming languages.14
The following table lists all operators in order of decreasing precedence:
Sendmail macros and
Bitwise shift left and right
< <= >= >
Relational operators (non-associative)
= != matches fnmatches
Equality and special comparison (non-associative)
Logical (bitwise) AND
Logical (bitwise) XOR
Logical (bitwise) OR
When two operands on each side of a binary expression have
mailfromd evaluator coerces them to a
common type. This is known as implicit type casting. The rules
for implicit type casting are:
The construct for explicit type cast is:
where type is the name of the type to coerce expr to. For example:
string(2 + 4*8) ⇒ "34"
The only exception is ‘not’, whose precedence in MFL is much lower than usual (in most programming languages it has the same precedence as unary ‘-’). This allows to write conditional expressions in more understandable manner. Consider the following condition:
if not x < 2 and y = 3
It is understood as “if
x is not less than 2 and
y equals 3”,
whereas with the usual precedence for ‘not’ it would have meant
x is less than 2 and
y equals 3”.
This document was generated on January 3, 2019 using makeinfo.Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.