1 { pkgs, lib, config, ... }:
 
   3   inherit (builtins) attrNames concatStringsSep readFile toPath;
 
   4   inherit (builtins.extraBuiltins) pass;
 
   6   inherit (pkgs.lib) loadFile unlines unwords unlinesAttrs;
 
   7   inherit (config) networking users;
 
   8   inherit (config.services) postfix dovecot2 openldap;
 
  12   postfix/sourcephile.fr.nix
 
  13   postfix/autogeree.net.nix
 
  17     tls_server_sni_maps = lib.mkOption {
 
  18       type = types.attrsOf (types.listOf types.path);
 
  20       apply = m: pkgs.writeText "sni" (lib.concatStringsSep "\n" (lib.mapAttrsToList (domain: x509: ''
 
  21         ${domain} ${unwords x509}
 
  27 users.groups.acme.members = [ postfix.user ];
 
  28 systemd.services.postfix = {
 
  29   after = ["openldap.service"];
 
  31     install -m 400 -o root -g root ${postfix.tls_server_sni_maps} /run/keys/postfix-sni
 
  32     ${pkgs.postfix}/bin/postmap -F hash:/run/keys/postfix-sni
 
  37   networksStyle = "host";
 
  38   hostname ="${networking.hostName}.${networking.domain}";
 
  39   domain = networking.domain;
 
  40   origin = "$myhostname";
 
  43     "localhost.localdomain"
 
  46   postmasterAlias = "root";
 
  47   rootAlias = "root@${networking.domain}";
 
  48   sslCert = loadFile (../../../sec/openssl + "/${networking.domain}/cert.self-signed.pem");
 
  49   sslKey = "/run/keys/${networking.domain}.key.pem";
 
  55   # Parse the extension in email address, eg. contact+extension@
 
  56   recipientDelimiter = "+";
 
  58     debug_peer_level = "4";
 
  60       #"chomsky.autogeree.net"
 
  62       #"mail.sourcephile.fr"
 
  66     # Sending to the world
 
  68     # Appending .domain is the MUA's job
 
  69     append_dot_mydomain = false;
 
  70     smtp_body_checks = "";
 
  71     #smtp_cname_overrides_servername = false;
 
  72     smtp_connect_timeout = "60s";
 
  73     #smtp_header_checks = "regexp:/var/lib/postfix/smtp_header_checks";
 
  74     smtp_mime_header_checks = "";
 
  75     smtp_nested_header_checks = "";
 
  76     smtp_tls_exclude_ciphers = [ "ADH" "MD5" "CAMELLIA" "SEED" "3DES" "DES" "RC4" "eNULL" "aNULL" ];
 
  77     #smtp_tls_fingerprint_digest = "sha1";
 
  78     smtp_tls_loglevel = "1";
 
  79     #smtp_tls_note_starttls_offer = true;
 
  80     #smtp_tls_policy_maps = "hash:/var/lib/postfix/conf/tls_policy";
 
  81     # Only allow TLSv* protocols
 
  82     smtp_tls_protocols = [ "!SSLv2" "!SSLv3" ];
 
  83     #smtp_tls_scert_verifydepth = "5";
 
  84     #smtp_tls_secure_cert_match = [ "nexthop" "dot-nexthop" ];
 
  85     smtp_tls_security_level = "may";
 
  86     smtp_tls_session_cache_database = "btree:$data_directory/smtp_tls_session_cache";
 
  87     #smtp_tls_session_cache_timeout = "3600s";
 
  88     #smtp_tls_verify_cert_match = "hostname";
 
  91     # Receiving from the world
 
  93     message_size_limit = "20480000";
 
  94     maximal_queue_lifetime = "5d";
 
  95     default_extra_recipient_limit = "5000";
 
  96     line_length_limit = "2048";
 
  97     duplicate_filter_limit = "5000";
 
  98     # Stops mail from poorly written software
 
  99     strict_rfc821_envelopes = true;
 
 100     mime_header_checks = [];
 
 101     milter_header_checks = [];
 
 102     nested_header_checks = [];
 
 105     permit_mx_backup_networks = [];
 
 106     propagate_unmatched_extensions = [ "canonical" "virtual" "alias" ];
 
 107     #masquerade_classes = [ "envelope_sender" "header_sender" "header_recipient" ];
 
 108     #masquerade_domains = "";
 
 109     #masquerade_exceptions = "root";
 
 111     # Stops some techniques used to harvest email addresses
 
 112     disable_vrfy_command = true;
 
 113     enable_long_queue_ids = false;
 
 114     # Useful to test restrictions
 
 115     smtpd_authorized_xclient_hosts = "127.0.0.1";
 
 116     smtpd_banner = "$myhostname ESMTP $mail_name (NixOS)";
 
 117     smtpd_client_connection_count_limit = "50";
 
 118     smtpd_client_connection_rate_limit = "0";
 
 119     smtpd_client_event_limit_exceptions = "$mynetworks";
 
 120     smtpd_client_message_rate_limit = "0";
 
 121     smtpd_client_new_tls_session_rate_limit = "0";
 
 122     smtpd_client_port_logging = false;
 
 123     smtpd_client_recipient_rate_limit = "0";
 
 125     smtpd_error_sleep_time = "5";
 
 126     # Needed to enforce reject_unknown_helo_hostname
 
 127     smtpd_helo_required = true;
 
 128     smtpd_helo_restrictions = [
 
 129       "reject_invalid_helo_hostname"
 
 130       "reject_non_fqdn_helo_hostname"
 
 131       # Don't talk to mail systems that don't know their own hostname.
 
 132       "reject_unknown_helo_hostname"
 
 135     smtpd_client_restrictions = [
 
 137     # Set in postfix/*.nix and used in submissions/smptd
 
 138     # with reject_sender_login_mismatch
 
 139     smtpd_sender_login_maps = [];
 
 140     smtpd_sender_restrictions = [
 
 141       "reject_non_fqdn_sender"
 
 144     smtpd_reject_unlisted_recipient = true;
 
 145     # Check the RCPT TO, before smtpd_recipient_restrictions
 
 146     # Restrictions based on what is allowed or not,
 
 147     # these are applied before smtpd_recipient_restrictions
 
 148     smtpd_relay_restrictions = [
 
 150       # Check the recipient's address in virtual_mailbox_domains and virtual_mailbox_maps
 
 151       "permit_auth_destination"
 
 152       # The world is only authorized to use our relay for the above destinations.
 
 155     # Restrictions based on what is working or not
 
 156     smtpd_recipient_restrictions = [
 
 157       # Reject if the domain is not fully qualified
 
 158       "reject_non_fqdn_recipient"
 
 159       # Reject if the domain is not working, even before bothering to check the address
 
 160       "reject_unknown_recipient_domain"
 
 161       # Reject if the address is not working
 
 162       # WARNING: verify(8) has a cache, dumpable if verify(8) is stopped, with:
 
 163       # postmap -s btree:/var/lib/postfix/data/verify_cache
 
 164       "reject_unverified_recipient"
 
 167     # Trust the verify database
 
 168     unverified_recipient_reject_code = "550";
 
 169     smtpd_data_restrictions = [
 
 170       # Force the smtpd's client to wait OK before sending
 
 171       "reject_unauth_pipelining"
 
 174     smtpd_end_of_data_restrictions = [
 
 175       # Enforce mail volume quota via policy service callouts.
 
 176       #check_policy_service unix:private/policy
 
 179     smtpd_peername_lookup = true;
 
 180     smtpd_recipient_limit = "5000";
 
 181     smtpd_recipient_overshoot_limit = "5000";
 
 182     #smtpd_restriction_classes = "";
 
 183     #smtpd_sasl_auth_enable = true;
 
 184     #smtpd_sasl_path = "private/auth";
 
 185     #smtpd_sasl_security_options = "noanonymous";
 
 186     #smtpd_sasl_type = "dovecot";
 
 187     smtpd_starttls_timeout = "300s";
 
 188     #smtpd_tls_always_issue_session_ids = true;
 
 189     #smtpd_tls_CApath = "/etc/postfix/x509/ca/";
 
 190     smtpd_tls_ask_ccert = false;
 
 191     #smtpd_tls_ccert_verifydepth = "5";
 
 192     smtpd_tls_ciphers = "high";
 
 193     smtpd_tls_eecdh_grade = "auto";
 
 194     # Disable weak ciphers as reported by https://ssl-tools.net
 
 195     # https://serverfault.com/questions/744168/how-to-disable-rc4-on-postfix
 
 196     smtpd_tls_exclude_ciphers = [ "ADH" "MD5" "CAMELLIA" "SEED" "3DES" "DES" "RC4" "eNULL" "aNULL" ];
 
 197     smtpd_tls_fingerprint_digest = "sha512";
 
 198     # Log only a summary message on TLS handshake completion
 
 199     smtpd_tls_loglevel = "1";
 
 200     smtpd_tls_mandatory_ciphers = "high";
 
 201     smtpd_tls_mandatory_protocols = [ "!SSLv2" "!SSLv3" ];
 
 203     smtpd_tls_protocols = [ "!SSLv2" "!SSLv3" ];
 
 204     #smtpd_tls_received_header = false;
 
 205     smtpd_tls_req_ccert = false;
 
 206     # Postfix 2.3 and later
 
 208     #  Mandatory TLS encryption: announce STARTTLS support to SMTP clients, and require that clients use TLS
 
 209     #  encryption. According to [1720]RFC 2487 this MUST NOT be applied in case of a publicly-referenced
 
 210     #  SMTP server. Instead, this option should be used only on dedicated servers.
 
 211     smtpd_tls_security_level = "may";
 
 212     smtpd_tls_session_cache_database = "btree:$data_directory/smtpd_tls_session_cache";
 
 213     #smtpd_tls_session_cache_timeout = "3600s";
 
 214     #smtpd_tls_chain_files =
 
 217     #relay_clientcerts = hash:/var/lib/postfix/conf/relay_clientcerts
 
 218     # This is where to put backup MX domains
 
 220     relay_recipient_maps = [];
 
 222     # Use a non blocking source of randomness
 
 223     tls_random_source = "dev:/dev/urandom";
 
 224     # Map each domain to a specific X.509 certificate
 
 225     tls_server_sni_maps = "hash:/run/keys/postfix-sni";
 
 227     # Only explicitely aliased accounts have a mail, not all the passwd
 
 228     local_recipient_maps = "$alias_maps";
 
 229     # Note that the local transport rewrites the envelope recipient
 
 230     # according to the alias_maps, and thus the aliasing is transparent
 
 231     # to the nexthop (eg. dovecot)
 
 232     #local_transport = local:$myhostname
 
 233     # No console bell on new mail
 
 237       "$home/.forward''${recipient_delimiter}''${extension}"
 
 242     # Filled by the postfix/*.nix
 
 243     virtual_mailbox_domains = [];
 
 244     # Completed by the postfix/*.nix
 
 245     virtual_mailbox_maps = [
 
 246       "hash:/etc/postfix/virtual"
 
 248     virtual_transport = "lmtp:unix:private/dovecot-lmtp";
 
 250     # There is no fallback
 
 251     fallback_transport = "";
 
 253   virtualMapType = "hash";
 
 258         then concatStringsSep "," value
 
 260           if value == true then "yes"
 
 261           else if value == false then "no"
 
 263       mkKeyVal = opt: val: [ "-o" (opt + "=" + mkVal val) ];
 
 264       mkArgs = args: lib.concatLists (lib.mapAttrsToList mkKeyVal args);
 
 268         cleanup_service_name = "submissions-header-cleanup";
 
 271     # Implicit TLS on port 465
 
 272     # https://tools.ietf.org/html/rfc8314#section-3.3
 
 278         syslog_name = "postfix/submissions";
 
 279         # Implicit TLS, not STARTTLS
 
 280         smtpd_tls_wrappermode = true;
 
 281         smtpd_tls_mandatory_protocols = [
 
 283           # K-9 Mail 5.600 still requires this..
 
 286         milter_macro_daemon_name = "ORIGINATING";
 
 287         smtpd_relay_restrictions = [
 
 288           # SASL authorizes to send to the world
 
 289           "permit_sasl_authenticated"
 
 292         smtpd_sasl_auth_enable = true;
 
 293         smtpd_sasl_type = "dovecot";
 
 294         smtpd_sasl_path = "private/auth";
 
 295         smtpd_sasl_local_domain = "";
 
 296         # Offer SASL authentication only after a TLS-encrypted session has been established
 
 297         smtpd_tls_auth_only = true;
 
 298         smtpd_sasl_tls_security_options = [ "noanonymous" ];
 
 299         # Do not put SASL logins in mail headers
 
 300         smtpd_sasl_authenticated_header = false;
 
 301         # Who cares about (old) Outlook
 
 302         broken_sasl_auth_clients = false;
 
 303         smtpd_sender_restrictions = [
 
 304           "reject_non_fqdn_sender"
 
 305           # Check that the SASL user is using only its own
 
 306           # mail addresses on the envelope, as indicated in smtpd_sender_login_maps
 
 307           "reject_sender_login_mismatch"
 
 310         # No X.509 certificates for users, for now
 
 311         smtpd_tls_ask_ccert = false;
 
 312         smtpd_tls_ccert_verifydepth = 0;
 
 313         smtpd_tls_loglevel = 1;
 
 314         smtpd_tls_req_ccert = false;
 
 315         cleanup_service_name = "submissions-header-cleanup";
 
 318     submissions-header-cleanup = {
 
 324         header_checks = "pcre:" + pkgs.writeText "submission_header_cleanup_rules" ''
 
 325           # Removes sensitive headers from mails handed in via the submission or smtps port.
 
 326           # See https://thomas-leister.de/mailserver-debian-stretch/
 
 327           # Uses "pcre" style regex.
 
 330           /^User-Agent:/       IGNORE
 
 331           /^X-Enigmail:/       IGNORE
 
 333           /^X-Originating-IP:/ IGNORE
 
 339     #spfcheck    unix  -        n       n       -        0        spawn
 
 340     #  user=policyd-spf argv=/usr/sbin/postfix-policyd-spf-perl
 
 341     # -o smtpd_sender_restrictions=reject_sender_login_mismatch
 
 342     # -o smtpd_sender_login_maps=hash:/etc/postfix/vaccounts
 
 343     # -o cleanup_service_name=submissions-header-cleanup
 
 344     #spfcheck  unix  -       n       n       -       0       spawn
 
 345     #  user=policyd-spf argv=/usr/bin/postfix-policyd-spf-perl
 
 346     #uucp      unix  -       n       n       -       -       pipe
 
 347     #  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
 
 348     #smtp      inet  n       -       -       -       -       smtpd
 
 349     #  -o cleanup_service_name=pre-cleanup
 
 350     #  -o content_filter=amavis:[127.0.0.1]:10024
 
 351     #  -o smtpd_sender_restrictions=reject_unauth_pipelining,reject_non_fqdn_sender,permit
 
 352     #  -o receive_override_options=no_address_mappings
 
 353     #amavis    unix  -       -       n        -      2       lmtp
 
 354     #  -o lmtp_data_done_timeout=1200
 
 355     #  -o lmtp_send_xforward_command=yes
 
 356     #  -o lmtp_tls_note_starttls_offer=no
 
 357     #127.0.0.1:10025 inet n  -       n       -       -       smtpd
 
 359     #  -o local_header_rewrite_clients=
 
 360     #  -o local_recipient_maps=
 
 361     #  -o mynetworks=127.0.0.0/8
 
 362     #  -o receive_override_options=no_header_body_checks,no_milters,no_unknown_recipient_checks
 
 363     #  -o relay_recipient_maps=
 
 364     #  -o smtpd_client_connection_count_limit=0
 
 365     #  -o smtpd_client_connection_rate_limit=0
 
 366     #  -o smtpd_client_restrictions=permit_mynetworks,reject
 
 367     #  -o smtpd_data_restrictions=reject_unauth_pipelining
 
 368     #  -o smtpd_delay_reject=no
 
 369     #  -o smtpd_end_of_data_restrictions=
 
 370     #  -o smtpd_error_sleep_time=0
 
 371     #  -o smtpd_hard_error_limit=1000
 
 372     #  -o smtpd_helo_restrictions=
 
 374     #  -o smtpd_recipient_restrictions=permit_mynetworks,reject
 
 375     #  -o smtpd_restriction_classes=
 
 376     #  -o smtpd_sender_restrictions=
 
 377     #  -o smtpd_soft_error_limit=1001
 
 378     #  -o strict_rfc821_envelopes=yes
 
 379     #submission inet n       -       -       -       -       smtpd
 
 380     #  -o cleanup_service_name=pre-cleanup
 
 381     #  -o content_filter=amavis:[127.0.0.1]:10024
 
 382     #  -o milter_macro_daemon_name=ORIGINATING
 
 383     #  -o receive_override_options=no_address_mappings
 
 384     #  -o smtpd_sender_restrictions=permit_tls_clientcerts,reject
 
 385     #  -o smtpd_tls_ask_ccert=yes
 
 386     #  -o smtpd_tls_auth_only=yes
 
 387     #  -o smtpd_tls_ccert_verifydepth=2
 
 388     #  -o smtpd_tls_loglevel=1
 
 389     #  -o smtpd_tls_req_ccert=yes
 
 390     #  -o smtpd_tls_security_level=encrypt
 
 391     #smtps     inet  n       -       -       -       -       smtpd
 
 392     #  -o milter_macro_daemon_name=ORIGINATING
 
 393     #  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 
 394     #  -o smtpd_sasl_auth_enable=yes
 
 395     #  -o smtpd_tls_ask_ccert=yes
 
 396     #  -o smtpd_tls_auth_only=yes
 
 397     #  -o smtpd_tls_ccert_verifydepth=0
 
 398     #  -o smtpd_tls_loglevel=1
 
 399     #  -o smtpd_tls_req_ccert=no
 
 400     #  -o smtpd_tls_security_level=encrypt
 
 401     #  -o smtpd_tls_wrappermode=yes
 
 402     #pickup    fifo  n       -       -       60      1       pickup
 
 403     #  -o cleanup_service_name=pre-cleanup
 
 404     #  -o content_filter=amavis:[127.0.0.1]:10024
 
 405     #pre-cleanup unix n      -       -       -       0       cleanup
 
 406     #  -o virtual_alias_maps=
 
 407     #cleanup   unix  n       -       -       -       0       cleanup
 
 408     #  -o mime_header_checks=
 
 409     #  -o nested_header_checks=
 
 413     #sympa unix - n n - - pipe
 
 414     #  flags=R user=sympa argv=/usr/lib/sympa/bin/queue ''${recipient}
 
 415     #sympabounce unix - n n - - pipe
 
 416     #  flags=R user=sympa argv=/usr/lib/sympa/bin/bouncequeue ''${recipient}
 
 419    #noclue    unix  -       n       n       -       -       pipe
 
 420    #  flags=q user=noclue argv=/usr/local/bin/noclue-delivery ${recipient} ${sender}