python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / mail / maddy.nix
blobeeb113e204c6eb56ebd7eb2a309db4961ec2a6db
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   name = "maddy";
9   cfg = config.services.maddy;
11   defaultConfig = ''
12     # Minimal configuration with TLS disabled, adapted from upstream example
13     # configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
14     # Do not use this in production!
16     tls off
18     auth.pass_table local_authdb {
19       table sql_table {
20         driver sqlite3
21         dsn credentials.db
22         table_name passwords
23       }
24     }
26     storage.imapsql local_mailboxes {
27       driver sqlite3
28       dsn imapsql.db
29     }
31     table.chain local_rewrites {
32       optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
33       optional_step static {
34         entry postmaster postmaster@$(primary_domain)
35       }
36       optional_step file /etc/maddy/aliases
37     }
38     msgpipeline local_routing {
39       destination postmaster $(local_domains) {
40         modify {
41           replace_rcpt &local_rewrites
42         }
43         deliver_to &local_mailboxes
44       }
45       default_destination {
46         reject 550 5.1.1 "User doesn't exist"
47       }
48     }
50     smtp tcp://0.0.0.0:25 {
51       limits {
52         all rate 20 1s
53         all concurrency 10
54       }
55       dmarc yes
56       check {
57         require_mx_record
58         dkim
59         spf
60       }
61       source $(local_domains) {
62         reject 501 5.1.8 "Use Submission for outgoing SMTP"
63       }
64       default_source {
65         destination postmaster $(local_domains) {
66           deliver_to &local_routing
67         }
68         default_destination {
69           reject 550 5.1.1 "User doesn't exist"
70         }
71       }
72     }
74     submission tcp://0.0.0.0:587 {
75       limits {
76         all rate 50 1s
77       }
78       auth &local_authdb
79       source $(local_domains) {
80         check {
81             authorize_sender {
82                 prepare_email &local_rewrites
83                 user_to_email identity
84             }
85         }
86         destination postmaster $(local_domains) {
87             deliver_to &local_routing
88         }
89         default_destination {
90             modify {
91                 dkim $(primary_domain) $(local_domains) default
92             }
93             deliver_to &remote_queue
94         }
95       }
96       default_source {
97         reject 501 5.1.8 "Non-local sender domain"
98       }
99     }
101     target.remote outbound_delivery {
102       limits {
103         destination rate 20 1s
104         destination concurrency 10
105       }
106       mx_auth {
107         dane
108         mtasts {
109           cache fs
110           fs_dir mtasts_cache/
111         }
112         local_policy {
113             min_tls_level encrypted
114             min_mx_level none
115         }
116       }
117     }
119     target.queue remote_queue {
120       target &outbound_delivery
121       autogenerated_msg_domain $(primary_domain)
122       bounce {
123         destination postmaster $(local_domains) {
124           deliver_to &local_routing
125         }
126         default_destination {
127             reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
128         }
129       }
130     }
132     imap tcp://0.0.0.0:143 {
133       auth &local_authdb
134       storage &local_mailboxes
135     }
136   '';
138 in {
139   options = {
140     services.maddy = {
142       enable = mkEnableOption (lib.mdDoc "Maddy, a free an open source mail server");
144       user = mkOption {
145         default = "maddy";
146         type = with types; uniq string;
147         description = lib.mdDoc ''
148           User account under which maddy runs.
150           ::: {.note}
151           If left as the default value this user will automatically be created
152           on system activation, otherwise the sysadmin is responsible for
153           ensuring the user exists before the maddy service starts.
154           :::
155         '';
156       };
158       group = mkOption {
159         default = "maddy";
160         type = with types; uniq string;
161         description = lib.mdDoc ''
162           Group account under which maddy runs.
164           ::: {.note}
165           If left as the default value this group will automatically be created
166           on system activation, otherwise the sysadmin is responsible for
167           ensuring the group exists before the maddy service starts.
168           :::
169         '';
170       };
172       hostname = mkOption {
173         default = "localhost";
174         type = with types; uniq string;
175         example = ''example.com'';
176         description = lib.mdDoc ''
177           Hostname to use. It should be FQDN.
178         '';
179       };
181       primaryDomain = mkOption {
182         default = "localhost";
183         type = with types; uniq string;
184         example = ''mail.example.com'';
185         description = lib.mdDoc ''
186           Primary MX domain to use. It should be FQDN.
187         '';
188       };
190       localDomains = mkOption {
191         type = with types; listOf str;
192         default = ["$(primary_domain)"];
193         example = [
194           "$(primary_domain)"
195           "example.com"
196           "other.example.com"
197         ];
198         description = lib.mdDoc ''
199           Define list of allowed domains.
200         '';
201       };
203       config = mkOption {
204         type = with types; nullOr lines;
205         default = defaultConfig;
206         description = lib.mdDoc ''
207           Server configuration, see
208           [https://maddy.email](https://maddy.email) for
209           more information. The default configuration of this module will setup
210           minimal maddy instance for mail transfer without TLS encryption.
212           ::: {.note}
213           This should not be used in a production environment.
214           :::
215         '';
216       };
218       openFirewall = mkOption {
219         type = types.bool;
220         default = false;
221         description = lib.mdDoc ''
222           Open the configured incoming and outgoing mail server ports.
223         '';
224       };
226     };
227   };
229   config = mkIf cfg.enable {
231     systemd = {
232       packages = [ pkgs.maddy ];
233       services.maddy = {
234         serviceConfig = {
235           User = cfg.user;
236           Group = cfg.group;
237           StateDirectory = [ "maddy" ];
238         };
239         restartTriggers = [ config.environment.etc."maddy/maddy.conf".source ];
240         wantedBy = [ "multi-user.target" ];
241       };
242     };
244     environment.etc."maddy/maddy.conf" = {
245       text = ''
246         $(hostname) = ${cfg.hostname}
247         $(primary_domain) = ${cfg.primaryDomain}
248         $(local_domains) = ${toString cfg.localDomains}
249         hostname ${cfg.hostname}
250         ${cfg.config}
251       '';
252     };
254     users.users = optionalAttrs (cfg.user == name) {
255       ${name} = {
256         isSystemUser = true;
257         group = cfg.group;
258         description = "Maddy mail transfer agent user";
259       };
260     };
262     users.groups = optionalAttrs (cfg.group == name) {
263       ${cfg.group} = { };
264     };
266     networking.firewall = mkIf cfg.openFirewall {
267       allowedTCPPorts = [ 25 143 587 ];
268     };
270     environment.systemPackages = [
271       pkgs.maddy
272     ];
273   };