Documentation and usage example for sieve script

This commit is contained in:
Gonne 2025-04-07 17:41:06 +02:00
parent 99bc6b7429
commit dd9b18dd18
Signed by: Gonne
SSH key fingerprint: SHA256:J8w3ZCNyz9MoTLV+eU7YRTVw59NYig44i0IWhbsgQG8
2 changed files with 68 additions and 0 deletions

View file

@ -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"]}

View file

@ -0,0 +1,64 @@
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:
```bash
$ ./alias_to_sieve testdata/simple.aliases example.com
```
```sieve
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, pass them all in one run: `$ ./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.