]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/services/mail/dovecot.nix
mermet: add dovecot
[sourcephile-nix.git] / nixos / modules / services / mail / dovecot.nix
1 { pkgs, lib, config, ... }:
2 let
3 inherit (builtins) toString toFile attrNames;
4 inherit (lib) types;
5 inherit (pkgs.lib) unlinesAttrs unlinesValues unwords;
6 inherit (config.services) dovecot2 openldap;
7 inherit (config) networking;
8 stateDir = "/var/lib/dovecot";
9 mailDir = "${stateDir}/mail";
10 sieveDir = "${stateDir}/sieve";
11 authDir = "${stateDir}/auth";
12 escapeGroup = lib.stringAsChars (c: if "a"<=c && c<="z"
13 || "0"<=c && c<="9"
14 || c=="-"
15 then c else "_");
16 domainGroup = escapeGroup "${networking.domainBase}";
17 in
18 {
19 options.services.dovecot2 = {
20 domains = lib.mkOption {
21 default = {};
22 type = types.attrsOf (types.submodule ({domain, ...}: {
23 #config.domain = lib.mkDefault domain;
24 options = {
25 accounts = lib.mkOption {
26 type = types.attrsOf (types.submodule ({account, ...}: {
27 options = {
28 password = lib.mkOption {
29 type = types.str;
30 example = "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
31 description = ''Password.
32 Use: `doveadm pw -s SSHA512 -p "$password"`
33 '';
34 };
35 aliases = lib.mkOption {
36 type = with types; listOf types.str;
37 example = [ "abuse@${config.networking.domain}" ];
38 default = [];
39 description = ''Aliases of this account.'';
40 };
41 quota = lib.mkOption {
42 type = with types; nullOr types.str;
43 default = null;
44 example = "2G";
45 description = ''
46 Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
47 obvious meaning. Leave blank for the standard quota `100G`.
48 '';
49 };
50 sieves = lib.mkOption {
51 type = with types; attrsOf str;
52 default = { main = ''
53 require ["include"];
54
55 #include :personal "roundcube";
56 include :global "spam";
57 include :global "list";
58 include :global "extension";
59 '';
60 };
61 };
62 groups = lib.mkOption {
63 type = with types; listOf str;
64 default = [];
65 };
66 };
67 }));
68 };
69 };
70 }));
71 };
72 debug = lib.mkOption {
73 type = types.bool;
74 default = false;
75 description = ''
76 Whether to enable verbose logging or not in mail related services.
77 '';
78 };
79 sieves = {
80 global = lib.mkOption {
81 description = "global scripts.";
82 type = types.attrsOf types.str;
83 default = {};
84 };
85 before = lib.mkOption {
86 description = "before scripts.";
87 type = types.attrsOf types.str;
88 default = {};
89 };
90 after = lib.mkOption {
91 description = "after scripts.";
92 type = types.attrsOf types.str;
93 default = {};
94 };
95 };
96 };
97
98 config = lib.mkIf dovecot2.enable {
99 systemd.services.dovecot2 = {
100 preStart = unlinesValues {
101 installMailDir = ''
102 # SEE: http://wiki2.dovecot.org/SharedMailboxes/Permissions
103 install -D -d -m 0771 \
104 -o ${dovecot2.mailUser} \
105 -g ${dovecot2.mailGroup} \
106 ${mailDir}
107 '';
108
109 installSieve = ''
110 rm -rf "${sieveDir}"
111 install -D -d -m 0755 -o root -g root \
112 "${sieveDir}/bin"
113 '' + unlinesAttrs (dir: sieves: ''
114 install -D -d -m 0755 -o root -g root \
115 ${sieveDir} ${sieveDir}/${dir}.d
116 '' + unlinesAttrs (name: text: ''
117 src=${pkgs.writeText "${name}.sieve" text}
118 dst="${sieveDir}/${dir}.d/${name}.sieve"
119 ln -fns "$src" "$dst"
120 ${pkgs.dovecot_pigeonhole}/bin/sievec "$dst"
121 '') sieves
122 ) dovecot2.sieves;
123
124 installDomains =
125 lib.optionalString openldap.enable ''
126 # NOTE: make sure nslcd cache is in sync with the LDAP data
127 systemctl restart nslcd
128 '' + ''
129 install -D -d -m 1770 \
130 -o ${dovecot2.mailUser} \
131 -g ${domainGroup} \
132 ${mailDir}/${networking.domain} \
133 ${stateDir}/control/${networking.domain} \
134 ${stateDir}/index/${networking.domain}
135
136 # NOTE: do not set the sticky bit (+t)
137 # on acl/<domain>/, to let dovecot
138 # rename acl.db.lock (own by new user)
139 # to acl.db (own by old user)
140 install -D -d -m 0770 \
141 -o ${dovecot2.mailUser} \
142 -g ${domainGroup} \
143 ${stateDir}/acl/${networking.domain}
144
145 # NOTE: domainAliases point to the very same mailboxes as domain's.
146 for domainAlias in ${unwords networking.domainAliases}
147 do
148 ln -fns ${networking.domain} ${mailDir}/$domainAlias
149 ln -fns ${networking.domain} ${stateDir}/control/$domainAlias
150 ln -fns ${networking.domain} ${stateDir}/index/$domainAlias
151 ln -fns ${networking.domain} ${stateDir}/acl/$domainAlias
152 done
153 '';
154 };
155 };
156 };
157 }