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);
17 "postfix/mysql_alias_maps" = {
18 user = config.services.postfix.user;
19 group = config.services.postfix.group;
22 # We need to specify that option to trigger ssl connection
24 user = ${config.myEnv.mail.postfix.mysql.user}
25 password = ${config.myEnv.mail.postfix.mysql.password}
26 hosts = ${config.myEnv.mail.postfix.mysql.remoteHost}
27 dbname = ${config.myEnv.mail.postfix.mysql.database}
28 query = SELECT DISTINCT 1
31 ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s'))
36 FROM forwardings_blacklisted
39 SELECT 'devnull@immae.eu'
40 FROM forwardings_blacklisted
44 "postfix/ldap_mailboxes" = {
45 user = config.services.postfix.user;
46 group = config.services.postfix.group;
49 server_host = ldaps://${config.myEnv.mail.dovecot.ldap.host}:636
50 search_base = ${config.myEnv.mail.dovecot.ldap.base}
51 query_filter = ${config.myEnv.mail.dovecot.ldap.postfix_mailbox_filter}
52 bind_dn = ${config.myEnv.mail.dovecot.ldap.dn}
53 bind_pw = ${config.myEnv.mail.dovecot.ldap.password}
54 result_attribute = immaePostfixAddress
59 "postfix/sympa_mailbox_maps" = {
60 user = config.services.postfix.user;
61 group = config.services.postfix.group;
64 hosts = ${config.myEnv.mail.sympa.postgresql.host}
65 user = ${config.myEnv.mail.sympa.postgresql.user}
66 password = ${config.myEnv.mail.sympa.postgresql.password}
67 dbname = ${config.myEnv.mail.sympa.postgresql.database}
68 query = SELECT DISTINCT 1 FROM list_table WHERE '%s' IN (
69 CONCAT(name_list, '@', robot_list),
70 CONCAT(name_list, '-request@', robot_list),
71 CONCAT(name_list, '-editor@', robot_list),
72 CONCAT(name_list, '-unsubscribe@', robot_list),
73 CONCAT(name_list, '-owner@', robot_list),
74 CONCAT('sympa-request@', robot_list),
75 CONCAT('sympa-owner@', robot_list),
76 CONCAT('sympa@', robot_list),
77 CONCAT('listmaster@', robot_list),
78 CONCAT('bounce@', robot_list),
79 CONCAT('abuse-feedback-report@', robot_list)
83 "postfix/ldap_ejabberd_users_immae_fr" = {
84 user = config.services.postfix.user;
85 group = config.services.postfix.group;
88 server_host = ldaps://${config.myEnv.jabber.ldap.host}:636
89 search_base = ${config.myEnv.jabber.ldap.base}
90 query_filter = ${config.myEnv.jabber.postfix_user_filter}
92 bind_dn = ${config.myEnv.jabber.ldap.dn}
93 bind_pw = ${config.myEnv.jabber.ldap.password}
94 result_attribute = immaeXmppUid
95 result_format = ejabberd@localhost
101 networking.firewall.allowedTCPPorts = [ 25 ];
103 users.users."${config.services.postfix.user}".extraGroups = [ "keys" ];
104 services.filesWatcher.postfix = {
107 config.secrets.fullPaths."postfix/mysql_alias_maps"
108 config.secrets.fullPaths."postfix/sympa_mailbox_maps"
109 config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"
110 config.secrets.fullPaths."postfix/ldap_mailboxes"
116 name = n: i: "relay_${n}_${toString i}";
117 pair = n: i: m: lib.attrsets.nameValuePair (name n i) (
119 then pkgs.writeText (name n i) m.content
122 pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps;
123 in lib.attrsets.filterAttrs (k: v: v != null) (
124 lib.attrsets.listToAttrs (lib.flatten (
125 lib.attrsets.mapAttrsToList pairs config.myEnv.mail.postfix.backup_domains
128 relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) (
129 lib.attrsets.mapAttrs' (n: v:
130 lib.attrsets.nameValuePair "recipient_access_${n}" (
131 if lib.attrsets.hasAttr "relay_restrictions" v
132 then pkgs.writeText "recipient_access_${n}" v.relay_restrictions
135 ) config.myEnv.mail.postfix.backup_domains
139 cfg = config.myEnv.monitoring.email_check.eldiron;
140 address = "${cfg.mail_address}@${cfg.mail_domain}";
141 in pkgs.writeText "postfix-virtual" (
142 builtins.concatStringsSep "\n" (
144 lib.attrsets.mapAttrsToList (
145 n: v: lib.optionalString v.external ''
146 script_${n}@mail.immae.eu 1
148 ) config.myEnv.mail.scripts
153 recipient_maps // relay_restrictions // virtual_map;
155 ### postfix module overrides
156 readme_directory = "${pkgs.postfix}/share/postfix/doc";
157 smtp_tls_CAfile = lib.mkForce "";
158 smtp_tls_cert_file = lib.mkForce "";
159 smtp_tls_key_file = lib.mkForce "";
161 message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited"
162 mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts
163 alias_database = "\$alias_maps";
167 backups = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) config.myEnv.mail.postfix.backup_domains);
168 virtual_domains = config.myEnv.mail.postfix.additional_mailbox_domains
169 ++ lib.remove null (lib.flatten (map
172 then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}"
175 (zone.withEmail or [])
177 config.myEnv.dns.masterZones
180 backups ++ virtual_domains;
181 relay_recipient_maps = let
182 backup_recipients = lib.flatten (lib.attrsets.mapAttrsToList (n: v:
183 lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps
184 ) config.myEnv.mail.postfix.backup_domains);
185 virtual_alias_maps = [
186 "hash:/etc/postfix/virtual"
187 "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"
188 "ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}"
190 virtual_mailbox_maps = [
191 "ldap:${config.secrets.fullPaths."postfix/ldap_mailboxes"}"
192 "pgsql:${config.secrets.fullPaths."postfix/sympa_mailbox_maps"}"
195 backup_recipients ++ virtual_alias_maps ++ virtual_mailbox_maps;
196 smtpd_relay_restrictions = [
197 "defer_unauth_destination"
198 ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v:
199 if lib.attrsets.hasAttr "relay_restrictions" v
200 then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ]
202 ) config.myEnv.mail.postfix.backup_domains);
204 ### Additional smtpd configuration
205 smtpd_tls_received_header = "yes";
206 smtpd_tls_loglevel = "1";
208 ### Email sending configuration
209 smtp_tls_security_level = "may";
210 smtp_tls_loglevel = "1";
212 ### Force ip bind for smtp
213 smtp_bind_address = config.myEnv.servers."${name}".ips.main.ip4;
214 smtp_bind_address6 = builtins.head config.myEnv.servers."${name}".ips.main.ip6;
217 "unix:${config.myServices.mail.milters.sockets.opendkim}"
218 "unix:${config.myServices.mail.milters.sockets.openarc}"
219 "unix:${config.myServices.mail.milters.sockets.opendmarc}"
224 enableSubmission = false;
225 destination = ["localhost"];
226 # This needs to reverse DNS
227 hostname = config.hostEnv.fqdn;
229 sslCert = "/var/lib/acme/mail/fullchain.pem";
230 sslKey = "/var/lib/acme/mail/key.pem";
231 recipientDelimiter = "+";