1 { pkgs, lib, config, ... }:
3 inherit (builtins) toString toFile attrNames;
5 inherit (pkgs.lib) unlinesAttrs unlinesValues unwords;
6 inherit (config.services) dovecot2 openldap;
7 inherit (config) networking;
8 stateDir = "/var/lib/dovecot";
9 escapeGroup = lib.stringAsChars (c: if "a"<=c && c<="z"
13 domainGroup = escapeGroup "${networking.domainBase}";
16 options.services.dovecot2 = {
17 domains = lib.mkOption {
19 type = types.attrsOf (types.submodule ({domain, ...}: {
20 #config.domain = lib.mkDefault domain;
22 accounts = lib.mkOption {
23 type = types.attrsOf (types.submodule ({account, ...}: {
25 password = lib.mkOption {
27 example = "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
28 description = ''Password.
29 Use: `doveadm pw -s SSHA512 -p "$password"`
32 aliases = lib.mkOption {
33 type = with types; listOf types.str;
34 example = [ "abuse@${config.networking.domain}" ];
36 description = ''Aliases of this account.'';
38 quota = lib.mkOption {
39 type = with types; nullOr types.str;
43 Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
44 obvious meaning. Leave blank for the standard quota `100G`.
47 groups = lib.mkOption {
48 type = with types; listOf str;
59 config = lib.mkIf dovecot2.enable {
60 systemd.services.dovecot2 = {
61 preStart = unlinesValues {
63 lib.optionalString openldap.enable ''
64 # NOTE: make sure nslcd cache is in sync with the LDAP data
65 systemctl restart nslcd
67 # SEE: http://wiki2.dovecot.org/SharedMailboxes/Permissions
68 install -D -d -m 0771 \
69 -o "${dovecot2.user}" \
70 -g "${dovecot2.group}" \
72 install -D -d -m 1770 \
73 -o "${dovecot2.user}" \
75 ${stateDir}/mail/${networking.domain} \
76 ${stateDir}/control/${networking.domain} \
77 ${stateDir}/index/${networking.domain}
79 # NOTE: do not set the sticky bit (+t)
80 # on acl/<domain>/, to let dovecot
81 # rename acl.db.lock (own by new user)
82 # to acl.db (own by old user)
83 install -D -d -m 0770 \
84 -o "${dovecot2.user}" \
86 ${stateDir}/acl/${networking.domain}
88 # NOTE: domainAliases point to the very same mailboxes as domain's.
89 for domainAlias in ${unwords networking.domainAliases}
91 ln -fns ${networking.domain} ${stateDir}/mail/$domainAlias
92 ln -fns ${networking.domain} ${stateDir}/control/$domainAlias
93 ln -fns ${networking.domain} ${stateDir}/index/$domainAlias
94 ln -fns ${networking.domain} ${stateDir}/acl/$domainAlias