1 { lib, pkgs, config, nodes, name, ... }:
3 config = lib.mkIf config.myServices.mailBackup.enable {
4 security.acme.certs."mail" = config.myServices.certificates.certConfig // {
6 systemctl restart postfix.service
8 domain = config.hostEnv.fqdn;
10 zonesWithMx = builtins.filter (zone:
11 lib.attrsets.hasAttr "withEmail" zone && lib.lists.length zone.withEmail > 0
12 ) config.myEnv.dns.masterZones;
13 mxs = map (zone: "${config.myEnv.servers."${name}".mx.subdomain}.${zone.name}") zonesWithMx;
14 in builtins.listToAttrs (map (mx: lib.attrsets.nameValuePair mx null) mxs);
18 dest = "postfix/mysql_alias_maps";
19 user = config.services.postfix.user;
20 group = config.services.postfix.group;
23 # We need to specify that option to trigger ssl connection
25 user = ${config.myEnv.mail.postfix.mysql.user}
26 password = ${config.myEnv.mail.postfix.mysql.password}
27 hosts = ${config.myEnv.mail.postfix.mysql.remoteHost}
28 dbname = ${config.myEnv.mail.postfix.mysql.database}
29 query = SELECT DISTINCT 1
30 FROM forwardings_merge
32 ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s'))
37 FROM forwardings_blacklisted
40 SELECT 'devnull@immae.eu'
41 FROM forwardings_blacklisted
46 dest = "postfix/mysql_mailbox_maps";
47 user = config.services.postfix.user;
48 group = config.services.postfix.group;
51 # We need to specify that option to trigger ssl connection
53 user = ${config.myEnv.mail.postfix.mysql.user}
54 password = ${config.myEnv.mail.postfix.mysql.password}
55 hosts = ${config.myEnv.mail.postfix.mysql.remoteHost}
56 dbname = ${config.myEnv.mail.postfix.mysql.database}
57 query = SELECT DISTINCT 1
61 (domain = '%d' AND user = '%u' AND regex = 0)
64 AND '%d' REGEXP CONCAT('^',domain,'$')
65 AND '%u' REGEXP CONCAT('^',user,'$')
72 dest = "postfix/ldap_ejabberd_users_immae_fr";
73 user = config.services.postfix.user;
74 group = config.services.postfix.group;
77 server_host = ldaps://${config.myEnv.jabber.ldap.host}:636
78 search_base = ${config.myEnv.jabber.ldap.base}
79 query_filter = ${config.myEnv.jabber.postfix_user_filter}
81 bind_dn = ${config.myEnv.jabber.ldap.dn}
82 bind_pw = ${config.myEnv.jabber.ldap.password}
83 result_attribute = immaeXmppUid
84 result_format = ejabberd@localhost
90 networking.firewall.allowedTCPPorts = [ 25 ];
92 nixpkgs.overlays = [ (self: super: {
93 postfix = super.postfix.override { withMySQL = true; };
95 users.users."${config.services.postfix.user}".extraGroups = [ "keys" ];
96 services.filesWatcher.postfix = {
99 config.secrets.fullPaths."postfix/mysql_alias_maps"
100 config.secrets.fullPaths."postfix/mysql_mailbox_maps"
101 config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"
107 name = n: i: "relay_${n}_${toString i}";
108 pair = n: i: m: lib.attrsets.nameValuePair (name n i) (
110 then pkgs.writeText (name n i) m.content
113 pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps;
114 in lib.attrsets.filterAttrs (k: v: v != null) (
115 lib.attrsets.listToAttrs (lib.flatten (
116 lib.attrsets.mapAttrsToList pairs config.myEnv.mail.postfix.backup_domains
119 relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) (
120 lib.attrsets.mapAttrs' (n: v:
121 lib.attrsets.nameValuePair "recipient_access_${n}" (
122 if lib.attrsets.hasAttr "relay_restrictions" v
123 then pkgs.writeText "recipient_access_${n}" v.relay_restrictions
126 ) config.myEnv.mail.postfix.backup_domains
129 virtual = pkgs.writeText "postfix-virtual" (
130 builtins.concatStringsSep "\n" (
131 lib.attrsets.mapAttrsToList (
132 n: v: lib.optionalString v.external ''
133 script_${n}@mail.immae.eu 1
135 ) config.myEnv.mail.scripts
140 host_dummy_mailboxes = pkgs.writeText "host-virtual-mailbox"
141 (builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (n: v: "${n}@immae.eu 1") nodes));
144 recipient_maps // relay_restrictions // virtual_map // sasl_access;
146 ### postfix module overrides
147 readme_directory = "${pkgs.postfix}/share/postfix/doc";
148 smtp_tls_CAfile = lib.mkForce "";
149 smtp_tls_cert_file = lib.mkForce "";
150 smtp_tls_key_file = lib.mkForce "";
152 message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited"
153 mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts
154 alias_database = "\$alias_maps";
158 backups = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) config.myEnv.mail.postfix.backup_domains);
159 virtual_domains = config.myEnv.mail.postfix.additional_mailbox_domains
160 ++ lib.remove "localhost.immae.eu" (lib.remove null (lib.flatten (map
163 then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}"
166 (zone.withEmail or [])
168 config.myEnv.dns.masterZones
171 backups ++ virtual_domains;
172 relay_recipient_maps = let
173 backup_recipients = lib.flatten (lib.attrsets.mapAttrsToList (n: v:
174 lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps
175 ) config.myEnv.mail.postfix.backup_domains);
176 virtual_alias_maps = [
177 "hash:/etc/postfix/virtual"
178 "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"
179 "ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}"
181 virtual_mailbox_maps = [
182 "hash:/etc/postfix/host_dummy_mailboxes"
183 "mysql:${config.secrets.fullPaths."postfix/mysql_mailbox_maps"}"
186 backup_recipients ++ virtual_alias_maps ++ virtual_mailbox_maps;
187 smtpd_relay_restrictions = [
188 "defer_unauth_destination"
189 ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v:
190 if lib.attrsets.hasAttr "relay_restrictions" v
191 then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ]
193 ) config.myEnv.mail.postfix.backup_domains);
195 ### Additional smtpd configuration
196 smtpd_tls_received_header = "yes";
197 smtpd_tls_loglevel = "1";
199 ### Email sending configuration
200 smtp_tls_security_level = "may";
201 smtp_tls_loglevel = "1";
203 ### Force ip bind for smtp
204 smtp_bind_address = config.myEnv.servers."${name}".ips.main.ip4;
205 smtp_bind_address6 = builtins.head config.myEnv.servers."${name}".ips.main.ip6;
208 "unix:${config.myServices.mail.milters.sockets.opendkim}"
209 "unix:${config.myServices.mail.milters.sockets.openarc}"
210 "unix:${config.myServices.mail.milters.sockets.opendmarc}"
215 enableSubmission = false;
216 # FIXME: Mail adressed to localhost.immae.eu will still have mx-1 as
217 # prioritized MX, which provokes "mail for localhost.immae.eu loops
218 # back to myself" errors. This transport entry forces to push
219 # e-mails to its right destination.
221 localhost.immae.eu smtp:[immae.eu]:25
223 destination = ["localhost"];
224 # This needs to reverse DNS
225 hostname = config.hostEnv.fqdn;
227 sslCert = "/var/lib/acme/mail/fullchain.pem";
228 sslKey = "/var/lib/acme/mail/key.pem";
229 recipientDelimiter = "+";