{ lib, pkgs, config, nodes, name, ... }: { config = lib.mkIf config.myServices.mailBackup.enable { security.acme2.certs."mail" = config.myServices.certificates.certConfig // { postRun = '' systemctl restart postfix.service ''; domain = config.hostEnv.fqdn; extraDomains = let zonesWithMx = builtins.filter (zone: lib.attrsets.hasAttr "withEmail" zone && lib.lists.length zone.withEmail > 0 ) config.myEnv.dns.masterZones; mxs = map (zone: "${config.myEnv.servers."${name}".mx.subdomain}.${zone.name}") zonesWithMx; in builtins.listToAttrs (map (mx: lib.attrsets.nameValuePair mx null) mxs); }; secrets.keys = [ { dest = "postfix/mysql_alias_maps"; user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; text = '' # We need to specify that option to trigger ssl connection tls_ciphers = TLSv1.2 user = ${config.myEnv.mail.postfix.mysql.user} password = ${config.myEnv.mail.postfix.mysql.password} hosts = ${config.myEnv.mail.postfix.mysql.remoteHost} dbname = ${config.myEnv.mail.postfix.mysql.database} query = SELECT DISTINCT 1 FROM forwardings_merge WHERE ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s')) AND active = 1 AND '%s' NOT IN ( SELECT source FROM forwardings_blacklisted WHERE source = '%s' ) UNION SELECT 'devnull@immae.eu' FROM forwardings_blacklisted WHERE source = '%s' ''; } { dest = "postfix/mysql_mailbox_maps"; user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; text = '' # We need to specify that option to trigger ssl connection tls_ciphers = TLSv1.2 user = ${config.myEnv.mail.postfix.mysql.user} password = ${config.myEnv.mail.postfix.mysql.password} hosts = ${config.myEnv.mail.postfix.mysql.remoteHost} dbname = ${config.myEnv.mail.postfix.mysql.database} query = SELECT DISTINCT 1 FROM mailboxes WHERE active = 1 AND ( (domain = '%d' AND user = '%u' AND regex = 0) OR ( regex = 1 AND '%d' REGEXP CONCAT('^',domain,'$') AND '%u' REGEXP CONCAT('^',user,'$') ) ) LIMIT 1 ''; } { dest = "postfix/ldap_ejabberd_users_immae_fr"; user = config.services.postfix.user; group = config.services.postfix.group; permissions = "0440"; text = '' server_host = ldaps://${config.myEnv.jabber.ldap.host}:636 search_base = ${config.myEnv.jabber.ldap.base} query_filter = ${config.myEnv.jabber.postfix_user_filter} domain = immae.fr bind_dn = ${config.myEnv.jabber.ldap.dn} bind_pw = ${config.myEnv.jabber.ldap.password} result_attribute = immaeXmppUid result_format = ejabberd@localhost version = 3 ''; } ]; networking.firewall.allowedTCPPorts = [ 25 ]; nixpkgs.overlays = [ (self: super: { postfix = super.postfix.override { withMySQL = true; }; }) ]; users.users."${config.services.postfix.user}".extraGroups = [ "keys" ]; services.filesWatcher.postfix = { restart = true; paths = [ config.secrets.fullPaths."postfix/mysql_alias_maps" config.secrets.fullPaths."postfix/mysql_mailbox_maps" config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr" ]; }; services.postfix = { mapFiles = let recipient_maps = let name = n: i: "relay_${n}_${toString i}"; pair = n: i: m: lib.attrsets.nameValuePair (name n i) ( if m.type == "hash" then pkgs.writeText (name n i) m.content else null ); pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps; in lib.attrsets.filterAttrs (k: v: v != null) ( lib.attrsets.listToAttrs (lib.flatten ( lib.attrsets.mapAttrsToList pairs config.myEnv.mail.postfix.backup_domains )) ); relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) ( lib.attrsets.mapAttrs' (n: v: lib.attrsets.nameValuePair "recipient_access_${n}" ( if lib.attrsets.hasAttr "relay_restrictions" v then pkgs.writeText "recipient_access_${n}" v.relay_restrictions else null ) ) config.myEnv.mail.postfix.backup_domains ); virtual_map = { virtual = let cfg = config.myEnv.monitoring.email_check.eldiron; address = "${cfg.mail_address}@${cfg.mail_domain}"; in pkgs.writeText "postfix-virtual" ( builtins.concatStringsSep "\n" ( ["${address} 1"] ++ lib.attrsets.mapAttrsToList ( n: v: lib.optionalString v.external '' script_${n}@mail.immae.eu 1 '' ) config.myEnv.mail.scripts ) ); }; sasl_access = { host_dummy_mailboxes = pkgs.writeText "host-virtual-mailbox" (builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (n: v: "${n}@immae.eu 1") nodes)); }; in recipient_maps // relay_restrictions // virtual_map // sasl_access; config = { ### postfix module overrides readme_directory = "${pkgs.postfix}/share/postfix/doc"; smtp_tls_CAfile = lib.mkForce ""; smtp_tls_cert_file = lib.mkForce ""; smtp_tls_key_file = lib.mkForce ""; message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited" mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts alias_database = "\$alias_maps"; ### Relay domains relay_domains = let backups = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) config.myEnv.mail.postfix.backup_domains); virtual_domains = config.myEnv.mail.postfix.additional_mailbox_domains ++ lib.remove null (lib.flatten (map (zone: map (e: if e.receive then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}" else null ) (zone.withEmail or []) ) config.myEnv.dns.masterZones )); in backups ++ virtual_domains; relay_recipient_maps = let backup_recipients = lib.flatten (lib.attrsets.mapAttrsToList (n: v: lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps ) config.myEnv.mail.postfix.backup_domains); virtual_alias_maps = [ "hash:/etc/postfix/virtual" "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}" "ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}" ]; virtual_mailbox_maps = [ "hash:/etc/postfix/host_dummy_mailboxes" "mysql:${config.secrets.fullPaths."postfix/mysql_mailbox_maps"}" ]; in backup_recipients ++ virtual_alias_maps ++ virtual_mailbox_maps; smtpd_relay_restrictions = [ "defer_unauth_destination" ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v: if lib.attrsets.hasAttr "relay_restrictions" v then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ] else [] ) config.myEnv.mail.postfix.backup_domains); ### Additional smtpd configuration smtpd_tls_received_header = "yes"; smtpd_tls_loglevel = "1"; ### Email sending configuration smtp_tls_security_level = "may"; smtp_tls_loglevel = "1"; ### Force ip bind for smtp smtp_bind_address = config.myEnv.servers."${name}".ips.main.ip4; smtp_bind_address6 = builtins.head config.myEnv.servers."${name}".ips.main.ip6; smtpd_milters = [ "unix:${config.myServices.mail.milters.sockets.opendkim}" "unix:${config.myServices.mail.milters.sockets.openarc}" "unix:${config.myServices.mail.milters.sockets.opendmarc}" ]; }; enable = true; enableSmtp = true; enableSubmission = false; destination = ["localhost"]; # This needs to reverse DNS hostname = config.hostEnv.fqdn; setSendmail = false; sslCert = "/var/lib/acme/mail/fullchain.pem"; sslKey = "/var/lib/acme/mail/key.pem"; recipientDelimiter = "+"; }; }; }