Rules and Actions

Rules and actions are the entry point to filter emails.


.vsl files in the rules directory accepts a special syntax: the rule and action keywords.


A rule is used to change the transaction state. It can accept and deny a transaction or simply proceed to the next rule using rule state functions. A rule is the main primitive for filtering.

<rule>      ::= "rule" <rule-name> "||" <expr>
<rule-name> ::= <string>
<expr>      ::= <rhai-expr> ; any valid Rhai expression. Must return a "state".

A BNF representation of a rule

// `state::deny()` is a function that return the `Deny` state.
// Thus, this rule denies any incoming transaction.
rule "deny all transactions" || state::deny(),

// Rhai expressions can be declared using the above inline syntax,
// or using code blocks, like bellow.
rule "check client ip" || {
    if ctx::client_ip() == "" {
        return state::faccept();
    } else {
        return state::next();

Declaring rules

As shown in the above example, a rule MUST return a β€œstate” (accept, deny, next, etc). Once the rule is executed and a state returned, vSMTP uses it to change the transaction state.

Rule engine state and effects are listed in the rule state reference.


An action is used to execute arbitrary code (logging, saving an email on disk, etc) without changing the transaction state.

<action>      ::= "action" <rule-name> "||" <expr>
<action-name> ::= <string>
<expr>        ::= <rhai-expr> ; any valid Rhai expression.

BNF representation of an action

// Write the email as json to a "backup" directory.
action "dump to disk" || fs::dump("backup"),

action "log incoming transaction" || {
    // Logging to /var/log/vsmtp.
    log("info", `new transaction: ${ctx::helo()} from ${ctx::client_ip()}`);

Declaring actions