main
nix 144 lines 5.23 KB
Raw
1 # This module makes it easy to define mailing lists in `simple-nixos-mailserver`
2 # with a couple of features:
3 #
4 # 1. We can (optionally) encrypt the forward addresses for increased privacy.
5 # 2. We can set up a login account for mailing addresses to allow sending
6 # email via `SMTP` from those addresses.
7
8 { config, lib, ... }:
9
10 let
11 inherit (lib) types;
12
13 fileToSecretId = file: builtins.baseNameOf file;
14
15 listsWithSecretPlaceholders = lib.mapAttrs' (name: mailingList: {
16 name = name;
17 value =
18 (lib.optional (mailingList.loginAccount != null && mailingList.loginAccount.storeEmail) name)
19 ++ map (
20 member:
21 if builtins.isString member then member else config.sops.placeholder.${fileToSecretId member}
22 ) mailingList.forwardTo;
23 }) config.mailing-lists;
24
25 secretAddressFiles = lib.pipe config.mailing-lists [
26 (lib.mapAttrsToList (_name: mailingList: mailingList.forwardTo))
27 lib.flatten
28 (builtins.filter (member: !builtins.isString member))
29 ];
30
31 secretPasswordFiles = lib.pipe config.mailing-lists [
32 (lib.filterAttrs (_name: mailingList: mailingList.loginAccount != null))
33 (lib.mapAttrsToList (_name: mailingList: mailingList.loginAccount.encryptedHashedPassword))
34 ];
35 in
36
37 {
38 options = {
39 mailing-lists = lib.mkOption {
40 type = types.attrsOf (
41 types.submodule {
42 options = {
43 forwardTo = lib.mkOption {
44 type = types.listOf (types.either types.str types.path);
45 default = [ ];
46 description = ''
47 Either a plaintext email address, or a path to an email address
48 encrypted with `nix run .#encrypt-email address`
49 '';
50 };
51 loginAccount = lib.mkOption {
52 type = types.nullOr (
53 types.submodule {
54 options = {
55 encryptedHashedPassword = lib.mkOption {
56 type = types.path;
57 description = ''
58 If specified, this enables sending emails from this address via SMTP.
59 Must be a path to encrypted file generated with `nix run .#encrypt-email login`
60 '';
61 };
62 storeEmail = lib.mkOption {
63 type = types.bool;
64 description = ''
65 Whether to store emails sent to this mailing list in a
66 mailbox accessible via IMAP.
67 '';
68 };
69 };
70 }
71 );
72 default = null;
73 };
74 };
75 }
76 );
77 description = ''
78 Mailing lists. Supports both forward-only mailing lists, as well as mailing
79 lists that allow sending via SMTP.
80 '';
81 };
82 };
83
84 config = {
85 assertions = lib.mapAttrsToList (name: mailingList: {
86 assertion = mailingList.forwardTo != [ ] || mailingList.loginAccount != null;
87 message = "Mailing list '${name}' must have either forwardTo addresses or a loginAccount configured";
88 }) config.mailing-lists;
89
90 mailserver.accounts = lib.pipe config.mailing-lists [
91 (lib.filterAttrs (_name: mailingList: mailingList.loginAccount != null))
92 (lib.mapAttrs (
93 _name: mailingList: {
94 hashedPasswordFile =
95 config.sops.secrets.${fileToSecretId mailingList.loginAccount.encryptedHashedPassword}.path;
96 }
97 ))
98 ];
99
100 # Declare secrets for every secret file.
101 sops.secrets = builtins.listToAttrs (
102 (map (file: {
103 name = fileToSecretId file;
104 value = {
105 format = "binary";
106 sopsFile = file;
107 };
108 }) secretAddressFiles)
109 ++ (map (file: {
110 name = fileToSecretId file;
111 value = {
112 format = "binary";
113 sopsFile = file;
114 # Need to restart `dovecot.service` to trigger `genPasswdScript` in
115 # `nixos-mailserver`:
116 # https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/blob/af7d3bf5daeba3fc28089b015c0dd43f06b176f2/mail-server/dovecot.nix#L369
117 # This could go away if sops-nix gets support for "input addressed secret
118 # paths": https://github.com/Mic92/sops-nix/issues/648
119 # Note: NixOS 26.05 renamed dovecot2.service to dovecot.
120 restartUnits = [ "dovecot.service" ];
121 };
122 }) secretPasswordFiles)
123 );
124
125 sops.templates."postfix-virtual-mailing-lists" = {
126 content = lib.concatStringsSep "\n" (
127 lib.mapAttrsToList (name: members: "${name} ${lib.concatStringsSep ", " members}") (
128 lib.filterAttrs (_name: members: builtins.length members > 0) listsWithSecretPlaceholders
129 )
130 );
131
132 # Need to restart postfix-setup to rerun `postmap` and generate updated `.db`
133 # files whenever mailing list membership changes.
134 # This could go away if sops-nix gets support for "input addressed secret
135 # paths": https://github.com/Mic92/sops-nix/issues/648
136 restartUnits = [ "postfix-setup.service" ];
137 };
138
139 services.postfix.mapFiles.virtual-mailing-lists =
140 config.sops.templates."postfix-virtual-mailing-lists".path;
141
142 services.postfix.settings.main.virtual_alias_maps = [ "hash:/etc/postfix/virtual-mailing-lists" ];
143 };
144 }