{ lib, config, ... }: let inherit (config) networking users; inherit (config.services) postfix; in { imports = [ #postfix/autogeree.net.nix #postfix/sourcephile.fr.nix ]; users.groups.acme.members = [ postfix.user ]; networking.nftables.ruleset = '' table inet filter { chain input-net { #tcp dport 25 counter accept comment "postfix: SMTP" #tcp dport 465 counter accept comment "postfix: submissions" } chain output-net { skuid ${postfix.user} tcp dport smtp counter accept comment "postfix: SMTP" } } ''; services.postfix = { enable = true; networksStyle = "host"; hostname = "${networking.hostName}.${networking.domain}"; domain = networking.domain; origin = "$myhostname"; destination = [ "localhost" "localhost.localdomain" "$myhostname" ]; postmasterAlias = "root"; rootAlias = "root@${networking.domain}"; sslKey = "/var/lib/acme/${networking.domain}/key.pem"; sslCert = "/var/lib/acme/${networking.domain}/fullchain.pem"; networks = [ "127.0.0.0/8" "[::1]/128" ]; setSendmail = true; # Parse the extension in email address, eg. contact+extension@ recipientDelimiter = "+"; config = { debug_peer_level = "4"; debug_peer_list = [ #"chomsky.autogeree.net" #"localhost" #"mail.sourcephile.fr" ]; # # Sending to the world # # Appending .domain is the MUA's job append_dot_mydomain = false; smtp_body_checks = ""; #smtp_cname_overrides_servername = false; smtp_connect_timeout = "60s"; #smtp_header_checks = "regexp:/var/lib/postfix/smtp_header_checks"; smtp_mime_header_checks = ""; smtp_nested_header_checks = ""; smtp_tls_exclude_ciphers = [ "ADH" "MD5" "CAMELLIA" "SEED" "3DES" "DES" "RC4" "eNULL" "aNULL" ]; #smtp_tls_fingerprint_digest = "sha1"; smtp_tls_loglevel = "1"; #smtp_tls_note_starttls_offer = true; #smtp_tls_policy_maps = "hash:/var/lib/postfix/conf/tls_policy"; # Only allow TLSv* protocols smtp_tls_protocols = [ "!SSLv2" "!SSLv3" ]; #smtp_tls_scert_verifydepth = "5"; #smtp_tls_secure_cert_match = [ "nexthop" "dot-nexthop" ]; smtp_tls_security_level = "may"; smtp_tls_session_cache_database = "btree:$data_directory/smtp_tls_session_cache"; #smtp_tls_session_cache_timeout = "3600s"; #smtp_tls_verify_cert_match = "hostname"; # # Receiving from the world # message_size_limit = "20480000"; maximal_queue_lifetime = "5d"; default_extra_recipient_limit = "5000"; line_length_limit = "2048"; duplicate_filter_limit = "5000"; # Stops mail from poorly written software strict_rfc821_envelopes = true; mime_header_checks = [ ]; milter_header_checks = [ ]; nested_header_checks = [ ]; body_checks = [ ]; content_filter = ""; permit_mx_backup_networks = [ ]; propagate_unmatched_extensions = [ "canonical" "virtual" "alias" ]; #masquerade_classes = [ "envelope_sender" "header_sender" "header_recipient" ]; #masquerade_domains = ""; #masquerade_exceptions = "root"; queue_minfree = "0"; # Stops some techniques used to harvest email addresses disable_vrfy_command = true; enable_long_queue_ids = false; # Useful to test restrictions smtpd_authorized_xclient_hosts = "127.0.0.1"; smtpd_banner = "$myhostname ESMTP $mail_name (NixOS)"; smtpd_client_connection_count_limit = "50"; smtpd_client_connection_rate_limit = "0"; smtpd_client_event_limit_exceptions = "$mynetworks"; smtpd_client_message_rate_limit = "0"; smtpd_client_new_tls_session_rate_limit = "0"; smtpd_client_port_logging = false; smtpd_client_recipient_rate_limit = "0"; # Ban 5 sec on error smtpd_error_sleep_time = "5"; # Needed to enforce reject_unknown_helo_hostname smtpd_helo_required = true; smtpd_helo_restrictions = [ "reject_invalid_helo_hostname" "reject_non_fqdn_helo_hostname" # Don't talk to mail systems that don't know their own hostname. "reject_unknown_helo_hostname" "permit" ]; smtpd_client_restrictions = [ ]; # Set in postfix/*.nix and used in submissions/smptd # with reject_sender_login_mismatch smtpd_sender_login_maps = [ ]; smtpd_sender_restrictions = [ "reject_non_fqdn_sender" "permit" ]; smtpd_reject_unlisted_recipient = true; # Check the RCPT TO, before smtpd_recipient_restrictions # Restrictions based on what is allowed or not, # these are applied before smtpd_recipient_restrictions smtpd_relay_restrictions = [ "permit_mynetworks" # Check the recipient's address in virtual_mailbox_domains and virtual_mailbox_maps "permit_auth_destination" # The world is only authorized to use our relay for the above destinations. "reject" ]; # Restrictions based on what is working or not smtpd_recipient_restrictions = [ # Reject if the domain is not fully qualified "reject_non_fqdn_recipient" # Reject if the domain is not working, even before bothering to check the address "reject_unknown_recipient_domain" # Reject if the address is not working # WARNING: this does not work if the recipient is greylisting. # WARNING: verify(8) has a cache, dumpable if verify(8) is stopped, with: # postmap -s btree:/var/lib/postfix/data/verify_cache #"reject_unverified_recipient" "permit" ]; # Trust the verify database #unverified_recipient_reject_code = "550"; smtpd_data_restrictions = [ # Force the smtpd's client to wait OK before sending "reject_unauth_pipelining" "permit" ]; smtpd_end_of_data_restrictions = [ # Enforce mail volume quota via policy service callouts. #check_policy_service unix:private/policy ]; #smtpd_milters = ""; smtpd_peername_lookup = true; smtpd_recipient_limit = "5000"; smtpd_recipient_overshoot_limit = "5000"; #smtpd_restriction_classes = ""; #smtpd_sasl_auth_enable = true; #smtpd_sasl_path = "private/auth"; #smtpd_sasl_security_options = "noanonymous"; #smtpd_sasl_type = "dovecot"; smtpd_starttls_timeout = "300s"; #smtpd_tls_always_issue_session_ids = true; #smtpd_tls_CApath = "/etc/postfix/x509/ca/"; smtpd_tls_ask_ccert = false; #smtpd_tls_ccert_verifydepth = "5"; smtpd_tls_ciphers = "high"; smtpd_tls_eecdh_grade = "auto"; # Disable weak ciphers as reported by https://ssl-tools.net # https://serverfault.com/questions/744168/how-to-disable-rc4-on-postfix smtpd_tls_exclude_ciphers = [ "ADH" "MD5" "CAMELLIA" "SEED" "3DES" "DES" "RC4" "eNULL" "aNULL" ]; smtpd_tls_fingerprint_digest = "sha512"; # Log only a summary message on TLS handshake completion smtpd_tls_loglevel = "1"; smtpd_tls_mandatory_ciphers = "high"; smtpd_tls_mandatory_protocols = [ "!SSLv2" "!SSLv3" ]; # Only allow TLSv* smtpd_tls_protocols = [ "!SSLv2" "!SSLv3" ]; #smtpd_tls_received_header = false; smtpd_tls_req_ccert = false; # Postfix 2.3 and later # encrypt # Mandatory TLS encryption: announce STARTTLS support to SMTP clients, and require that clients use TLS # encryption. According to [1720]RFC 2487 this MUST NOT be applied in case of a publicly-referenced # SMTP server. Instead, this option should be used only on dedicated servers. smtpd_tls_security_level = "may"; smtpd_tls_session_cache_database = "btree:$data_directory/smtpd_tls_session_cache"; #smtpd_tls_session_cache_timeout = "3600s"; #smtpd_tls_chain_files = relayhost = [ ]; #relay_clientcerts = hash:/var/lib/postfix/conf/relay_clientcerts # This is where to put backup MX domains relay_domains = [ ]; relay_recipient_maps = [ ]; # Use a non blocking source of randomness tls_random_source = "dev:/dev/urandom"; # Map each domain to a specific X.509 certificate tls_server_sni_maps = "hash:/run/postfix/postfix-sni"; # Only explicitely aliased accounts have a mail, not all the passwd #local_recipient_maps = "$alias_maps"; # Note that the local transport rewrites the envelope recipient # according to the alias_maps, and thus the aliasing is transparent # to the nexthop (eg. dovecot) local_transport = "local:$myhostname"; # No console bell on new mail biff = false; forward_path = [ /* "$home/.forward''${recipient_delimiter}''${extension}" */ "$home/.forward" ]; # Filled by the postfix/*.nix virtual_mailbox_domains = [ ]; # Completed by the postfix/*.nix virtual_mailbox_maps = [ #"hash:/etc/postfix/virtual" ]; #virtual_transport = "lmtp:unix:private/dovecot-lmtp"; /* dovecot_destination_recipient_limit = "1"; virtual_transport = "dovecot"; */ # There is no fallback fallback_transport = ""; }; transport = '' sourcephile.wg local:losurdo ''; virtualMapType = "hash"; masterConfig = let mkVal = value: if lib.isList value then lib.concatStringsSep "," value else if value == true then "yes" else if value == false then "no" else toString value; mkKeyVal = opt: val: [ "-o" (opt + "=" + mkVal val) ]; mkArgs = args: lib.concatLists (lib.mapAttrsToList mkKeyVal args); in { pickup = { args = mkArgs { cleanup_service_name = "submissions-header-cleanup"; }; }; /* # Implicit TLS on port 465 # https://tools.ietf.org/html/rfc8314#section-3.3 submissions = { type = "inet"; private = false; command = "smtpd"; args = mkArgs { syslog_name = "postfix/submissions"; # Implicit TLS, not STARTTLS smtpd_tls_wrappermode = true; smtpd_tls_mandatory_protocols = [ "TLSv1.3" # FIXME: to be removed when K-9 Mail will support TLSv1.3, # K-9 Mail 5.600 does not. "TLSv1.2" ]; milter_macro_daemon_name = "ORIGINATING"; smtpd_helo_restrictions = [ "permit_sasl_authenticated" ] ++ postfix.config.smtpd_helo_restrictions; smtpd_relay_restrictions = [ # SASL authorizes to send to the world "permit_sasl_authenticated" "reject" ]; smtpd_sasl_auth_enable = true; smtpd_sasl_type = "dovecot"; smtpd_sasl_path = "private/auth"; smtpd_sasl_local_domain = ""; # Offer SASL authentication only after a TLS-encrypted session has been established smtpd_tls_auth_only = true; smtpd_sasl_tls_security_options = [ "noanonymous" ]; # Do not put SASL logins in mail headers smtpd_sasl_authenticated_header = false; # Who cares about (old) Outlook broken_sasl_auth_clients = false; smtpd_sender_restrictions = [ "reject_non_fqdn_sender" # Check that the SASL user is using only its own # mail addresses on the envelope, as indicated in smtpd_sender_login_maps "reject_sender_login_mismatch" "permit" ]; # No X.509 certificates for users, for now smtpd_tls_ask_ccert = false; smtpd_tls_ccert_verifydepth = 0; smtpd_tls_loglevel = 1; smtpd_tls_req_ccert = false; cleanup_service_name = "submissions-header-cleanup"; }; }; */ }; extraMasterConf = '' ''; }; }