Merge branch 'sieve-migration' into 'main'

sieve: move `cfg.sieveDirectory` into home directory of virtual users

See merge request simple-nixos-mailserver/nixos-mailserver!508
This commit is contained in:
Martin Weinelt
2026-05-24 03:07:38 +00:00
11 changed files with 376 additions and 74 deletions
+10
View File
@@ -132,5 +132,15 @@ in
'';
}
]
++ lib.optionals (config.mailserver.enableManageSieve) [
{
assertion = config.mailserver.stateVersion != null -> config.mailserver.stateVersion >= 5;
message = ''
NixOS Mailserver requires moving the Sieve script directories into Dovecot home directories.
Check https://nixos-mailserver.readthedocs.io/en/latest/migrations.html#sieve-script-directory-migration for required migration steps.
'';
}
]
);
}
+17 -3
View File
@@ -346,14 +346,28 @@ in
"sieve_script default" = {
# declarative
type = "default";
path = "${cfg.sieveDirectory}/%{user}/default.sieve";
name = "default";
# TODO: Pre-compile Sieve scripts with 'sievec' (requires a Dovecot config in build sandbox)
path = "${
pkgs.runCommand "declarative-sieve-scripts" { } (
''
mkdir "$out"
''
+ lib.concatMapAttrsStringSep "\n" (_: value: ''
mkdir "$out/${value.name}"
cp -v "${builtins.toFile "default.sieve" value.sieveScript}" "$out/${value.name}/default.sieve"
'') (lib.filterAttrs (_: value: value.sieveScript != null) cfg.accounts)
)
}/%{user}/default.sieve";
};
"sieve_script personal" = {
# managesieve
type = "personal";
active_path = "${cfg.sieveDirectory}/%{user}/active.sieve";
path = "${cfg.sieveDirectory}/%{user}/scripts";
# Upstream default, but we want to be explicit about it
# https://doc.dovecot.org/main/core/plugins/sieve.html#script-storage-type-personal
active_path = "~/.dovecot.sieve";
path = "~/sieve";
};
sieve_extensions = {
-56
View File
@@ -16,59 +16,12 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.mailserver;
virtualMailUsersActivationScript =
pkgs.writeScript "activate-virtual-mail-users"
# bash
''
#!${pkgs.stdenv.shell}
set -euo pipefail
# Prevent world-readable paths, even temporarily.
umask 007
# Create directory to store user sieve scripts if it doesn't exist
if (! test -d "${cfg.sieveDirectory}"); then
mkdir "${cfg.sieveDirectory}"
chown "${cfg.storage.owner}:${cfg.storage.group}" "${cfg.sieveDirectory}"
chmod 770 "${cfg.sieveDirectory}"
fi
# Copy user's sieve script to the correct location (if it exists). If it
# is null, remove the file.
${lib.concatMapStringsSep "\n" (
{ name, sieveScript }:
if lib.isString sieveScript then
''
if (! test -d "${cfg.sieveDirectory}/${name}"); then
mkdir -p "${cfg.sieveDirectory}/${name}"
chown "${cfg.storage.owner}:${cfg.storage.group}" "${cfg.sieveDirectory}/${name}"
chmod 770 "${cfg.sieveDirectory}/${name}"
fi
cat << 'EOF' > "${cfg.sieveDirectory}/${name}/default.sieve"
${sieveScript}
EOF
chown "${cfg.storage.owner}:${cfg.storage.group}" "${cfg.sieveDirectory}/${name}/default.sieve"
''
else
''
if (test -f "${cfg.sieveDirectory}/${name}/default.sieve"); then
rm "${cfg.sieveDirectory}/${name}/default.sieve"
fi
if (test -f "${cfg.sieveDirectory}/${name}.svbin"); then
rm "${cfg.sieveDirectory}/${name}/default.svbin"
fi
''
) (map (user: { inherit (user) name sieveScript; }) (lib.attrValues cfg.accounts))}
'';
in
{
config = lib.mkIf cfg.enable {
@@ -107,14 +60,5 @@ in
home = cfg.storage.path;
createHome = true;
};
systemd.services.activate-virtual-mail-users = {
wantedBy = [ "multi-user.target" ];
before = [ "dovecot.service" ];
serviceConfig = {
ExecStart = virtualMailUsersActivationScript;
};
enable = true;
};
};
}