{ pkgs , lib , config , ... }: let domain = config.networking.domain; components = lib.strings.splitString "." domain; dcComponents = map (x: "dc=" + x) components; ldapPath = builtins.concatStringsSep "," dcComponents; ldapServer = "ldap.${domain}"; domains = pkgs.writeText "domains.cf" '' server_host = ldap://${ldapServer} search_base = ou=domains,${ldapPath} version = 3 bind = yes start_tls = yes bind_dn = cn=vmail,ou=system,ou=users,${ldapPath} bind_pw = @ldap-password@ scope = one query_filter = (&(dc=%s)(objectClass=mailDomain)) result_attribute = postfixTransport debuglevel = 0 ''; mailboxes = pkgs.writeText "mailboxes.cf" '' server_host = ldap://${ldapServer} search_base = ou=users,dc=%2,dc=%1 version = 3 bind = yes start_tls = yes bind_dn = cn=vmail,ou=system,ou=users,${ldapPath} bind_pw = @ldap-password@ scope = sub query_filter = (&(uid=%u)(objectClass=mailAccount)) result_attribute = mail debuglevel = 0 ''; senderLoginMaps = pkgs.writeText "sender_login_maps.cf" '' server_host = ldap://${ldapServer} search_base = dc=%2,dc=%1 version = 3 bind = yes start_tls = yes bind_dn = cn=vmail,ou=system,ou=users,${ldapPath} bind_pw = @ldap-password@ scope = sub query_filter = (|(&(objectClass=mailAccount)(uid=%u))(&(objectClass=mailAlias)(mail=%s))) result_attribute = maildrop, mail debuglevel = 0 ''; accountsmap = pkgs.writeText "accountsmap.cf" '' server_host = ldap://${ldapServer} search_base = ou=users,dc=%2,dc=%1 version = 3 bind = yes start_tls = yes bind_dn = cn=vmail,ou=system,ou=users,${ldapPath} bind_pw = @ldap-password@ scope = sub query_filter = (&(objectClass=mailAccount)(uid=%u)) result_attribute = mail debuglevel = 0 ''; aliases = pkgs.writeText "aliases.cf" '' server_host = ldap://${ldapServer} search_base = ou=aliases,dc=%2,dc=%1 version = 3 bind = yes start_tls = yes bind_dn = cn=vmail,ou=system,ou=users,${ldapPath} bind_pw = @ldap-password@ scope = one query_filter = (&(objectClass=mailAlias)(mail=%s)) result_attribute = maildrop debuglevel = 0 ''; helo_access = pkgs.writeText "helo_access" '' /^([0-9\.]+)$/ REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1}) ${domain} REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1}) ghetto.at REJECT ACCESS DENIED. Your email was rejected because the sending mail server sent non RFC compliant HELO identity (''${1}) ''; in { services.postfix = { enable = true; enableSubmission = true; hostname = "mail.${domain}"; domain = domain; masterConfig."465" = { type = "inet"; private = false; command = "smtpd"; args = [ "-o smtpd_client_restrictions=permit_sasl_authenticated,reject" "-o syslog_name=postfix/smtps" "-o smtpd_tls_wrappermode=yes" "-o smtpd_sasl_auth_enable=yes" "-o smtpd_tls_security_level=none" "-o smtpd_reject_unlisted_recipient=no" "-o smtpd_recipient_restrictions=" "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject" "-o milter_macro_daemon_name=ORIGINATING" ]; }; mapFiles."helo_access" = helo_access; config = { # debug_peer_list = "10.42.96.190"; # smtp_bind_address = config.networking.eve.ipv4.address; # smtp_bind_address6 = "2a01:4f9:2b:1605::1"; mailbox_transport = "lmtp:unix:private/dovecot-lmtp"; virtual_mailbox_domains = "ldap:/run/postfix/domains.cf"; virtual_mailbox_maps = "ldap:/run/postfix/mailboxes.cf"; virtual_alias_maps = "ldap:/run/postfix/accountsmap.cf,ldap:/run/postfix/aliases.cf"; virtual_transport = "lmtp:unix:private/dovecot-lmtp"; smtpd_sender_login_maps = "ldap:/run/postfix/sender_login_maps.cf"; # Do not display the name of the recipient table in the "User unknown" responses. # The extra detail makes trouble shooting easier but also reveals information # that is nobody elses business. show_user_unknown_table_name = "no"; compatibility_level = "2"; # bigger attachement size mailbox_size_limit = "202400000"; message_size_limit = "51200000"; smtpd_helo_required = "yes"; smtpd_delay_reject = "yes"; strict_rfc821_envelopes = "yes"; # send Limit smtpd_error_sleep_time = "1s"; smtpd_soft_error_limit = "10"; smtpd_hard_error_limit = "20"; smtpd_use_tls = "yes"; smtp_tls_note_starttls_offer = "yes"; smtpd_tls_security_level = "may"; smtpd_tls_auth_only = "yes"; smtp_dns_support_level = "dnssec"; smtp_tls_security_level = "dane"; smtpd_tls_cert_file = "/var/lib/acme/mail.${domain}/full.pem"; smtpd_tls_key_file = "/var/lib/acme/mail.${domain}/key.pem"; smtpd_tls_CAfile = "/var/lib/acme/mail.${domain}/fullchain.pem"; smtpd_tls_dh512_param_file = config.security.dhparams.params.postfix512.path; smtpd_tls_dh1024_param_file = config.security.dhparams.params.postfix2048.path; smtpd_tls_session_cache_database = ''btree:''${data_directory}/smtpd_scache''; smtpd_tls_mandatory_protocols = "!SSLv2,!SSLv3,!TLSv1,!TLSv1.1"; smtpd_tls_protocols = "!SSLv2,!SSLv3,!TLSv1,!TLSv1.1"; smtpd_tls_mandatory_ciphers = "medium"; tls_medium_cipherlist = "AES128+EECDH:AES128+EDH"; # authentication smtpd_sasl_auth_enable = "yes"; smtpd_sasl_local_domain = "$mydomain"; smtpd_sasl_security_options = "noanonymous"; smtpd_sasl_tls_security_options = "$smtpd_sasl_security_options"; smtpd_sasl_type = "dovecot"; smtpd_sasl_path = "/var/lib/postfix/queue/private/auth"; smtpd_relay_restrictions = " permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination"; smtpd_client_restrictions = " permit_mynetworks, permit_sasl_authenticated, reject_invalid_hostname, reject_unknown_client, permit"; smtpd_helo_restrictions = " permit_mynetworks, permit_sasl_authenticated, reject_unauth_pipelining, reject_non_fqdn_hostname, reject_invalid_hostname, warn_if_reject reject_unknown_hostname, permit"; smtpd_recipient_restrictions = " permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_non_fqdn_hostname, reject_invalid_hostname, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unknown_client_hostname, reject_unauth_pipelining, reject_unknown_client, permit"; smtpd_sender_restrictions = " reject_non_fqdn_sender, reject_unlisted_sender, reject_authenticated_sender_login_mismatch, permit_mynetworks, permit_sasl_authenticated, reject_unknown_sender_domain, reject_unknown_client_hostname, reject_unknown_address"; smtpd_etrn_restrictions = "permit_mynetworks, reject"; smtpd_data_restrictions = "reject_unauth_pipelining, reject_multi_recipient_bounce, permit"; }; }; systemd.tmpfiles.rules = [ "d /run/postfix 0750 postfix postfix -" ]; systemd.services.postfix.preStart = '' sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${domains} > /run/postfix/domains.cf sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${mailboxes} > /run/postfix/mailboxes.cf sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${accountsmap} > /run/postfix/accountsmap.cf sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${aliases} > /run/postfix/aliases.cf sed -e "s/@ldap-password@/$(cat ${config.sops.secrets.dovecot-ldap-password.path})/" ${senderLoginMaps} > /run/postfix/sender_login_maps.cf ''; security.dhparams = { enable = true; params.postfix512.bits = 512; params.postfix2048.bits = 1024; }; security.acme.certs."mail.${domain}" = { extraDomainNames = [ "mail-test.${domain}" "mail-02.${domain}" ]; postRun = "systemctl restart postfix.service"; group = "postfix"; }; networking.firewall.allowedTCPPorts = [ 25 # smtp 465 # smtps 587 # submission ]; }