From a66e37de94b12e9e3bd08a7aec2284692f76f48c Mon Sep 17 00:00:00 2001 From: Gonne Date: Mon, 7 Apr 2025 17:41:06 +0200 Subject: [PATCH] Documentation and usage example for sieve script --- packages/alias-to-sieve/Cargo.toml | 4 ++ packages/alias-to-sieve/README.md | 62 ++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 packages/alias-to-sieve/README.md diff --git a/packages/alias-to-sieve/Cargo.toml b/packages/alias-to-sieve/Cargo.toml index 77b7e28..488dab9 100644 --- a/packages/alias-to-sieve/Cargo.toml +++ b/packages/alias-to-sieve/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2021" rust-version = "1.68.2" +description = "Convert an alias file to a sieve script for stalwart-mail" +readme = "README.md" +license = " AGPL-3.0-only" +keywords = ["mail", "sieve", "alias", "stalwart"] [dependencies] fqdn = {version = "0.4.2", features = ["domain-label-length-limited-to-63", "domain-name-without-special-chars"]} diff --git a/packages/alias-to-sieve/README.md b/packages/alias-to-sieve/README.md new file mode 100644 index 0000000..7edc130 --- /dev/null +++ b/packages/alias-to-sieve/README.md @@ -0,0 +1,62 @@ +This script converts an alias file to a sieve script for [stalwart-mail](https://stalw.art/). + +## Usage +Given an alias file `testdata/simple.aliases` that contains lines of redirects of the form localpart with optional `@fqdn` followed by a space followed by a list (space or comma+space separated) list of destinations that consist of a localpart and optionally an `@fqdn`. +If you don't define a fqdn along any of the addresses, the default domain from your commandline input will be appended. + +An example using the testdata directory of this repository: +``` +$ ./alias_to_sieve testdata/simple.aliases example.com +require ["variables", "copy", "vnd.stalwart.expressions", "envelope", "editheader"]; + +let "i" "0"; +while "i < count(envelope.to)" { + let "redirected" "false"; + if eval "eq_ignore_case(envelope.to[i], 'admin@example.com')" { + addheader "Delivered-To" "admin@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "admin@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'postmaster@example.com')" { + addheader "Delivered-To" "postmaster@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "postmaster@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'root@example.com')" { + addheader "Delivered-To" "root@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "root@example.com"; + let "redirected" "true"; + } + if eval "eq_ignore_case(envelope.to[i], 'sudo@example.com')" { + addheader "Delivered-To" "sudo@example.com"; + redirect :copy "me@example.org"; + + deleteheader :index 1 :is "Delivered-To" "sudo@example.com"; + let "redirected" "true"; + } + if eval "!redirected" { + let "destination" "envelope.to[i]"; + redirect :copy "${destination}"; + } + let "i" "i+1"; +} +discard; + +``` + +If you have multiple domains with multiple alias files, do `$ ./alias_to_sieve simple.aliases example.com other.aliases example.org`. + +## Limitations +You cannot use apostrophes (') in any mail addresses although allowed by [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322) since they would break termination of strings in sieve. + +This parser is not designed with security in mind. While the above gives some basic protection against code injection, I have no idea whether sieve has other pitfalls that might allow them. + +This is my first rust project, consume the code with care. + +The generated code is specific to stalwart-mail and contains non-standard sieve features.