General-Purpose Mail Filter
A function is a named
mailfromd subroutine, which
takes zero or more parameters and optionally returns a certain
value. Depending on the return value, functions can be
subdivided into string functions and number functions.
A function may have mandatory and optional parameters.
When invoked, the function must be supplied exactly as many
actual arguments as the number of its mandatory parameters.
Functions are invoked using the following syntax:
where name is the function name and args is a comma-separated list of expressions. For example, the following are valid function calls:
foo(10) interval("1 hour") greylist("/var/my.db", 180)
The number of parameters a function takes and their data types compose the function signature. When actual arguments are passed to the function, they are converted to types of the corresponding formal parameters.
There are two major groups of functions: built-in functions,
that are implemented in the
mailfromd binary, and
user-defined functions, that are written in MFL. The
invocation syntax is the same for both groups.
Mailfromd is shipped with a rich set of library
functions. These are described in Library. In addition to
these you can define your own functions.
Function definitions can appear anywhere between the handler declarations in a filter program, the only requirement being that the function definition occur before the place where the function is invoked.
The syntax of a function definition is:
[qualifier] func name (param-decl) returns data-type do function-body done
where name is the name of the function to define, param-decl is a comma-separated list of parameter declarations. The syntax of the latter is the same as that of variable declarations (see Variable declarations), i.e.:
declares the parameter name having the type type. The
Optional qualifier declares the scope of visibility for that function (see scope of visibility). It is similar to that of variables, except that functions cannot be local (i.e. you cannot declare function within another function).
public qualifier declares a function that may be referred
to from any module, whereas the
static qualifier declares a
function that may be called only from the current module
(see Modules). The default scope is ‘public’,
unless specified otherwise in the module declaration (see module structure).
For example, the following declares a function ‘sum’, that takes two numeric arguments and returns a numeric value:
func sum(number x, number y) returns number
Similarly, the following is a declaration of a static function:
static func sum(number x, number y) returns number
Parameters are referenced in the function-body by their name,
the same way as other variables. Similarly, the value of a parameter can be
A function can be declared to take a certain number of optional
arguments. In a function declaration, optional abstract arguments
must be placed after the mandatory ones, and must be separated from
them with a semicolon. The following example is a definition of
foo, which takes two mandatory and two optional
func foo(string msg, string email; number x, string pfx)
Mandatory parameters are:
pfx. The actual number of
arguments supplied to the function is returned by a special construct
$#. In addition, the special construct
evaluates to the ordinal number of variable arg in the list of
formal parameters (the first argument has number ‘0’). These two
constructs can be used to verify whether an argument is supplied to
When an actual argument for parameter
n is supplied, the number
of actual arguments (
$#) is greater than the ordinal number
of that parameter in the declaration list (
the following construct can be used to check if an optional argument
arg is actually supplied:
func foo(string msg, string email; number x, string arg) do if $# > @arg … fi
mailfromd installation provides a special
macro for this purpose: see defined. Using it, the example above
could be rewritten as:
func foo(string msg, string email; number x, string arg) do if defined(arg) … fi
Within a function body, optional arguments are referenced exactly the same way as the mandatory ones. Attempt to dereference an optional argument for which no actual parameter was supplied, results in an undefined value, so be sure to check whether a parameter is passed before dereferencing it.
A function can also take variable number of arguments (such
functions are called variadic). This is
indicated by the use of ellipsis as the last abstract parameter. The
statement below defines a function
foo taking one mandatory, one
optional and any number of additional arguments:
func foo (string a ; string b, ...)
All actual arguments passed in a list of variable arguments are coerced to string data type. To refer to these arguments in the function body, the following construct is used:
where expr is any valid MFL expression, evaluating to
a number n. This construct refers to the value of nth
actual parameter from the variable argument list. Parameters are
numbered from ‘1’, so the first variable parameter is
and the last one is
$($# - Nm - No), where Nm
and No are numbers of mandatory and optional parameters to the
For example, the function below prints all its arguments:
func pargs (string text, ...) do echo "text=%text" loop for number i 1, while i <= $# - 1, set i i + 1 do echo "arg %i=" . $(i) done done
Note the loop limits. The last variable argument has number
- 1, because the function takes one mandatory argument.
The function-body is any list of valid
statements. In addition to the statements discussed below
(see Statements) it can also contain the
which is used to return a value from the function. The syntax of the
return statement is
As an example of this, consider the following code snippet that defines the function ‘sum’ to return a sum of its two arguments:
func sum(number x, number y) returns number do return x + y done
returns part in the function declaration is optional. A
declaration lacking it defines a procedure, or void
function, i.e. a function that is not supposed to return any value.
Such functions cannot be used in expressions, instead they are
used as statements (see Statements). The following example
shows a function that emits a customized temporary failure notice:
func stdtf() do tempfail 451 4.3.5 "Try again later" done
A function may have several names. An alternative name (or
alias) can be assigned to a function by using
keyword, placed after param-decl part, for example:
func foo() alias bar returns string do … done
After this declaration, both
bar() will refer
to the same function.
The number of function aliases is unlimited. The following fragment declares a function having three names:
func foo() alias bar alias baz returns string do … done
Although this feature is rarely needed, there are sometimes cases when it may be necessary.
A variable declared within a function becomes a local variable to
this function. Its lexical scope ends with the terminating
Parameters, local variables and global variables are using separate namespaces, so a parameter name can coincide with the name of a global, in which case a parameter is said to shadow the global. All references to its name will refer to the parameter, until the end of its scope is reached, where the global one becomes visible again. Consider the following example:
number x func foo(string x) do echo "foo: %x" done prog envfrom do set x "Global" foo("Local") echo x done
mailfromd --test with this configuration will
foo: Local Global
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.