global::state

Functions used to interact with the rule engine. Use states in rules to deny, accept, or quarantine emails.

fn faccept

fn faccept() -> Status
fn faccept(code: SharedObject) -> Status
fn faccept(code: String) -> Status
Tell the rule engine to force accept the incoming transaction. This means that all rules following the one `faccept` is called will be ignored.

Use this return status when you are sure that the incoming client can be trusted.

  • code - A customized code as a string or code object. (default: β€œ250 Ok”)
  • The object passed as parameter was not a code object.
  • The string passed as parameter failed to be parsed into a valid code.

all of them.

#{
    connect: [
        // Here we imagine that "192.168.1.10" is a trusted source, so we can force accept
        // any other rules that don't need to be run.
        rule "check for trusted source" || if ctx::client_ip() == "192.168.1.10" { faccept() } else { state::next() },
    ],

    // The following rules will not be evaluated if `ctx::client_ip() == "192.168.1.10"` is true.
    mail: [
        rule "another rule" || {
            // ... doing stuff
        }
    ],
}

#{
    mail: [
        rule "send a custom code with a code object" || {
            faccept(code(220, "Ok"))
        }
    ],
}

#{
    mail: [
        rule "send a custom code with a string" || {
            faccept("220 Ok")
        }
    ],
}

fn accept

fn accept() -> Status
fn accept(code: SharedObject) -> Status
fn accept(code: String) -> Status
Tell the rule engine to accept the incoming transaction for the current stage. This means that all rules following the one `accept` is called in the current stage will be ignored.
  • code - A customized code as a string or code object. (default: β€œ250 Ok”)
  • The object passed as parameter was not a code object.
  • The string passed as parameter failed to be parsed into a valid code.

all of them.

#{
    connect: [
        // "ignored checks" will be ignored because the previous rule returned accept.
        rule "accept" || state::accept(),
        action "ignore checks" || print("this will be ignored because the previous rule used state::accept()."),
    ],

    mail: [
        // rule evaluation is resumed in the next stage.
        rule "resume rules" || print("evaluation resumed!");
    ]
}

#{
    mail: [
        rule "send a custom code with a code object" || {
            accept(code(220, "Ok"))
        }
    ],
}

#{
    mail: [
        rule "send a custom code with a string" || {
            accept("220 Ok")
        }
    ],
}

fn next

fn next() -> Status
Tell the rule engine that a rule succeeded. Following rules in the current stage will be executed.

all of them.

#{
    connect: [
        // once "go to the next rule" is evaluated, the rule engine execute "another rule".
        rule "go to the next rule" || state::next(),
        action "another rule" || print("checking stuff ..."),
    ],
}

fn deny

fn deny() -> Status
fn deny(code: String) -> Status
fn deny(code: SharedObject) -> Status
Stop rules evaluation and send an error code to the client.
  • code - A customized code as a string or code object. (default: β€œ554 permanent problems with the remote server”)
  • The object passed as parameter was not a code object.
  • The string passed as parameter failed to be parsed into a valid code.

all of them.

#{
    rcpt: [
        rule "check for satan" || {
           // The client is denied if a recipient's domain matches satan.org,
           // this is a blacklist, sort-of.
           if ctx::rcpt().domain == "satan.org" {
               state::deny()
           } else {
               state::next()
           }
       },
    ],
}

#{
    mail: [
        rule "send a custom code with a code object" || {
            deny(code(421, "Service not available"))
        }
    ],
}

#{
    mail: [
        rule "send a custom code with a string" || {
            deny("450 mailbox unavailable")
        }
    ],
}

fn quarantine

fn quarantine(queue: String) -> Status
Skip all rules until the email is received and place the email in a quarantine queue. The email will never be sent to the recipients and will stop being processed after the `PreQ` stage.
  • queue - the relative path to the queue where the email will be quarantined as a string. This path will be concatenated to the config.app.dirpath field in your root configuration.

all of them.

import "services" as svc;

#{
    postq: [
          delegate svc::clamsmtpd "check email for virus" || {
              // the email is placed in quarantined if a virus is detected by
              // a service.
              if has_header("X-Virus-Infected") {
                state::quarantine("virus_queue")
              } else {
                state::next()
              }
          }
    ],
}

op ==

op ==(status_1: Status, status_2: Status) -> bool
Check if two statuses are equal.

all of them.

#{
    connect: [
        action "check status equality" || {
            deny() == deny(); // returns true.
            faccept() == next(); // returns false.
        }
    ],
}

op !=

op !=(status_1: Status, status_2: Status) -> bool
Check if two statuses are not equal.

all of them.

#{
    connect: [
        action "check status not equal" || {
            deny() != deny(); // returns false.
            faccept() != next(); // returns true.
        }
    ],
}

fn to_string

fn to_string(status: Status) -> String
Convert a status to a string. Enables string interpolation.

all of them.

#{
    connect: [
        rule "status to string" || {
            let status = next();
            // `.to_string` is called automatically here.
            log("info", `converting my status to a string: ${status}`);
            status
        }
    ],
}

fn to_debug

fn to_debug(status: Status) -> String
Convert a status to a debug string Enables string interpolation.

all of them.

#{
    connect: [
        rule "status to string" || {
            let status = next();
            log("info", `converting my status to a string: ${status.to_debug()}`);
            status
        }
    ],
}