# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 PortSystem 1.0 PortGroup active_variants 1.1 name mail-server version 1.5 revision 1 categories mail net platforms darwin supported_archs noarch maintainers {ieee.org:s.t.smith @essandess} openmaintainer license GPL-3 distfiles description Mail server configuration long_description Mail server working configuration that \ provides a basic, working, easily modifiable \ mail server. The configuration is built using \ postfix for the MTA, dovecot for the MDA, solr \ for fast search, rspamd for a milter, and \ clamav for email virus scans. The \ configuration includes a surrogate TLS \ certificate, DKIM, and Apple Push Notification \ Service (APNS) capability for iOS devices. homepage https://www.postfix.org/ set postfix_required_variants \ [lsort {dovecot_sasl pcre smtputf8 tls}] set dovecot_required_variants \ [lsort {solr}] depends_lib-append port:dcc \ port:dovecot \ port:dovecot-sieve \ path:bin/openssl:openssl \ port:postfix \ port:rspamd \ port:sf-pwgen # these dependencies are from variants that may not be active depends_lib-append port:apache-solr8 \ port:clucene \ port:curl \ port:expat \ port:pcre depends_run-append port:clamav-server variant initialize_always \ description {Always initialize all configuration files. Intended \ for development and troubleshooting only. Working deployments \ must disable this variant to prevent configuration files \ being overwritten at the next upgrade. Existing configuration \ files are not overwritten by default.} { ui_warn \ " \tAll configuration files will be initialized because \tthe variant +initialize_always is set. Please disable \tthis variant for working deployments. " } variant logrotate \ description {Use mail-server logrotate configuration.} { depends_lib-append port:logrotate } default_variants-append +logrotate use_configure no require_active_variants postfix ${postfix_required_variants} require_active_variants dovecot ${dovecot_required_variants} build {} set certificates_dir ${prefix}/etc/certificates set tls_ca_dir ${certificates_dir}/ca.macports # random 4-word-based passphrase proc correct_horse_battery_staple {} { # ignore errors from sf-pwgen if the password is shorter than requested return \ [join [exec sh -c "sf-pwgen \ --algorithm memorable --count 2 --length 16 \ 2>/dev/null || true"] -] } destroot { # configuration design: MacPorts file and/or directory templates installed # to *.macports, then edited with local network settings, then in # post-activate copied to actual configuration files if such don't exist # common foreach d [list \ var/log/mail \ etc/certificates \ var/spool/postfix${prefix}/var/run/rspamd \ var/run/redis \ ] { xinstall -m 0750 -o root -g mail -d ${destroot}${prefix}/${d} destroot.keepdirs-append ${destroot}${prefix}/${d} } # postfix xinstall -m 0755 -d ${destroot}${prefix}/etc/postfix xinstall -m 0755 -d ${destroot}${prefix}/etc/postfix/etc/pam.d xinstall -m 0750 -o root -g _postfix -d ${destroot}${prefix}/etc/postfix/sasl xinstall -m 0755 -o root -g _postfix -d ${destroot}${prefix}/var/spool/postfix/etc xinstall -m 0755 -o root -g mail -d \ ${destroot}${prefix}/etc/postfix/etc \ ${destroot}${prefix}/etc/postfix/etc/certificates \ ${destroot}${prefix}/etc/postfix/etc/pam.d # *.macports templates foreach f { main.cf master.cf sasl/passwd } { xinstall -m 0644 \ ${filespath}/prefix/etc/postfix/${f} \ ${destroot}${prefix}/etc/postfix/${f}.macports } # generic templates foreach f { master.cf.chroot master.cf.nochroot smtp.keytab.README.sh etc/pam.d/smtp } { xinstall -m 0644 \ ${filespath}/prefix/etc/postfix/${f} \ ${destroot}${prefix}/etc/postfix/${f} } # chroot jail necessities xinstall -m 0644 /etc/hosts ${destroot}${prefix}/var/spool/postfix/etc xinstall -m 0644 /etc/services ${destroot}${prefix}/var/spool/postfix/etc # dovecot xinstall -m 0755 -d ${destroot}${prefix}/etc/dovecot # *.macports templates foreach d { conf.d } { xinstall -m 0755 -d \ ${destroot}${prefix}/etc/dovecot/${d}.macports destroot.keepdirs-append \ ${destroot}${prefix}/etc/dovecot/${d}.macports } foreach d { sieve sieve-before.d sieve-afer.d } { xinstall -m 0755 -g mail -d \ ${destroot}${prefix}/etc/dovecot/${d}.macports destroot.keepdirs-append \ ${destroot}${prefix}/etc/dovecot/${d}.macports } foreach f { dovecot.conf } { xinstall -m 0644 \ ${filespath}/prefix/etc/dovecot/${f} \ ${destroot}${prefix}/etc/dovecot/${f}.macports } foreach d { conf.d sieve sieve-before.d sieve-afer.d } { foreach f [glob -nocomplain ${filespath}/prefix/etc/dovecot/${d}/*] { if {[file isfile ${f}]} { xinstall -m 0644 ${f} \ ${destroot}${prefix}/etc/dovecot/${d}.macports/[file tail ${f}] } } } # generic templates foreach d { default example-config etc/pam.d } { xinstall -m 0755 -d \ ${destroot}${prefix}/etc/dovecot/${d} } foreach f { etc/pam.d/imap imap.keytab.README.sh } { xinstall -m 0644 \ ${filespath}/prefix/etc/dovecot/${f} \ ${destroot}${prefix}/etc/dovecot/${f} } foreach d { default example-config } { foreach f [glob -nocomplain ${filespath}/prefix/etc/dovecot/${d}/*] { if {[file isfile ${f}]} { xinstall -m 0644 ${f} \ ${destroot}${prefix}/etc/dovecot/${d}/[file tail ${f}] } } } # rspamd xinstall -m 0755 -d ${destroot}${prefix}/etc/rspamd foreach d { local.d } { xinstall -m 0755 -d ${destroot}${prefix}/etc/rspamd/${d}.macports foreach f [glob -nocomplain ${filespath}/prefix/etc/rspamd/${d}/*] { if {[file isfile ${f}]} { xinstall -m 0644 ${f} \ ${destroot}${prefix}/etc/rspamd/${d}.macports/[file tail ${f}] } } } foreach f { dkim_paths.map dkim_selectors.map } { xinstall -m 0644 ${filespath}/prefix/etc/rspamd/${f} \ ${destroot}${prefix}/etc/rspamd/${f}.macports } # redis foreach f { redis.conf } { xinstall -m 0644 ${filespath}/prefix/etc/${f} \ ${destroot}${prefix}/etc/${f}.macports } # dcc xinstall -m 0755 -d ${destroot}${prefix}/etc/dcc foreach f { dcc_conf } { xinstall -m 0644 ${filespath}/prefix/etc/dcc/${f} \ ${destroot}${prefix}/etc/dcc/${f}.macports } # logrotate if { [variant_isset "logrotate"] } { foreach d { logrotate.d } { xinstall -m 0755 -d ${destroot}${prefix}/etc/${d}.macports foreach f [glob -nocomplain ${filespath}/prefix/etc/${d}/*] { if {[file isfile ${f}]} { xinstall -m 0644 ${f} \ ${destroot}${prefix}/etc/${d}.macports/[file tail ${f}] } } } foreach f { logrotate.conf } { xinstall -m 0644 ${filespath}/prefix/etc/${f} \ ${destroot}${prefix}/etc/${f}.macports } } # TLS certificate surrogate xinstall -m 0755 -d ${destroot}${certificates_dir} xinstall -m 0700 -d ${destroot}${certificates_dir}/private destroot.keepdirs-append \ ${destroot}${certificates_dir} \ ${destroot}${certificates_dir}/private xinstall -m 0755 -d ${destroot}${tls_ca_dir} xinstall -m 0755 -d ${destroot}${tls_ca_dir}/intermediate xinstall -m 0644 \ ${filespath}/prefix/etc/certificates/ca/openssl.cnf \ ${destroot}${tls_ca_dir} xinstall -m 0644 \ ${filespath}/prefix/etc/certificates/ca/intermediate/openssl_intermediate.cnf \ ${destroot}${tls_ca_dir}/intermediate if { [variant_isset "initialize_always"] && [file exists ${tls_ca_dir}] } { delete ${tls_ca_dir}.previous move \ ${tls_ca_dir} \ ${tls_ca_dir}.previous } } destroot.keepdirs ${destroot}${prefix}/var/log/mail # Workaround for issue with dovecot version 2.3.17 on macOS 12 # https://www.mail-archive.com/dovecot@dovecot.org/msg84784.html if {${os.platform} eq "darwin" && ${os.major} >= 21} { post-destroot { system -W ${destroot}${prefix}/etc/dovecot/conf.d.macports \ "${patch.cmd} ${patch.pre_args} < ${filespath}/patch-10-master.conf.diff" } } pre-activate { # mail-server 1.1 inadvertently installed org.macports.logrotate.plist # into /Library/LaunchDaemons # https://trac.macports.org/ticket/60273 # This cleanup hack can be removed after December 2023. if { ![variant_isset "logrotate"] } { delete /Library/LaunchDaemons/org.macports.logrotate.plist } } proc plutil_startup {plcmds label} { global prefix startupitem.location foreach cmd ${plcmds} { system -W ${prefix}/etc/${startupitem.location}/${label} \ "/usr/bin/plutil ${cmd} ${label}.plist" } } # Network configuration # hard-coded examples set host host set domain domain set tld tld set fullhost ${host}.${domain}.${tld} set domaintld ${domain}.${tld} set HOST [string toupper ${host}] set DOMAIN [string toupper ${domain}] set TLD [string toupper ${tld}] set FULLHOST [string toupper ${fullhost}] set DOMAINTLD [string toupper ${domaintld}] set relayhost mymailrelay.tld post-activate { # modify the launch daemons plutil_startup [list \ "-remove KeepAlive" \ "-insert RunAtLoad -bool YES" \ ] \ org.macports.${name} # Cf. port logrotate's ${prefix}/share/logrotate/org.macports.logrotate.plist.example if { [variant_isset "logrotate"] } { plutil_startup [list \ "-remove KeepAlive" \ "-insert RunAtLoad -bool YES" \ "-replace ProgramArguments \ -xml ' \ ${prefix}/sbin/logrotate \ ${prefix}/etc/logrotate.conf \ '" \ "-insert StartCalendarInterval \ -xml ' \ Hour \ 5 \ Minute \ 30 \ '" \ ] \ org.macports.${name}.logrotate } # use network settings for installed example configuration set fullhost [exec /bin/hostname -f] if { [llength [split ${fullhost} .]] >= 3 } { set host [lindex [split ${fullhost} .] 0] set domaintld [join [lrange [split ${fullhost} .] 1 end] .] set domain [lindex [split ${domaintld} .] 0] set tld [lindex [split ${domaintld} .] end] } set HOST [string toupper ${host}] set DOMAIN [string toupper ${domain}] set TLD [string toupper ${tld}] set FULLHOST [string toupper ${fullhost}] set DOMAINTLD [string toupper ${domaintld}] set rspamd_control_password \ [correct_horse_battery_staple] set rspamd_control_password_hash \ [exec rspamadm pw --password ${rspamd_control_password}] ui_msg "Configuring Mail Server with: host : ${host} domain : ${domain} tld : ${tld} " proc install_initial_configuration {f_or_d} { if { [variant_isset "initialize_always"] && [file exists ${f_or_d}] } { delete ${f_or_d}.previous move \ ${f_or_d} \ ${f_or_d}.previous } if { [variant_isset "initialize_always"] || ![file exists ${f_or_d}] } { if { [file isfile ${f_or_d}.macports] } { xinstall -m 0644 \ ${f_or_d}.macports \ ${f_or_d} } elseif { [file isdirectory ${f_or_d}.macports] } { xinstall -m 0755 -d ${f_or_d} foreach f [glob -nocomplain ${f_or_d}.macports/*] { xinstall -m 0644 ${f} \ ${f_or_d}/[file tail ${f}] } } } } # postfix configuration foreach f_or_d { main.cf master.cf sasl/passwd } { install_initial_configuration ${prefix}/etc/postfix/${f_or_d} } # postfix relay host and password surrogate file attributes ${prefix}/etc/postfix/sasl/passwd \ -group _postfix -permissions 0640 # dovecot configuration foreach f_or_d { dovecot.conf conf.d sieve sieve-before.d sieve-afer.d } { install_initial_configuration ${prefix}/etc/dovecot/${f_or_d} } xinstall -m 0770 -g mail -d /private/var/mail/${tld}.${domain}.mail/ xinstall -m 0777 -g mail -d /private/var/mail/${tld}.${domain}.mail/attachments/ # solr configuration if { [variant_isset "initialize_always"] } { system "sudo -u solr -g solr sh </dev/null || true solr8 start -p 8983 2>/dev/null || true solr8 delete -c dovecot 2>/dev/null || true solr8 stop -p 8983 2>/dev/null || true SOLR_DELETE_DOVECOT " } # create dovecot core; wrap commands in shell to avoid non-zero # return value if it already exists system "sudo -u solr -g solr sh -c \ \"solr8 stop -p 8983 2>/dev/null || true\"" system "sudo -u solr -g solr sh -c \ \"solr8 start -p 8983 2>/dev/null || true\"" set solr_version [exec solr8 version] system "sudo -u solr -g solr sh -c \ \"solr8 create -c dovecot -n dovecot 2>/dev/null || true\"" system "sudo -u solr -g solr sh -c \ \"solr8 stop -p 8983 2>/dev/null || true\"" if { ![file exists ${prefix}/var/solr/dovecot/conf/] } { ui_error \ "solr directory ${prefix}/var/solr/dovecot/conf/ doesn't exist." exit 1 } # See Tips at https://wiki.dovecot.org/Plugins/FTS/Solr # wget -O solrconfig.xml https://github.com/dovecot/core/raw/master/doc/solr-config-7.7.0.xml xinstall -b -B.orig -g solr -m 0644 -o solr \ ${filespath}/prefix/var/solr/dovecot/conf/solrconfig.xml \ ${prefix}/var/solr/dovecot/conf/solrconfig.xml # wget -O schema.xml https://github.com/dovecot/core/raw/master/doc/solr-schema-7.7.0.xml xinstall -b -B.orig -g solr -m 0644 -o solr \ ${filespath}/prefix/var/solr/dovecot/conf/schema.xml \ ${prefix}/var/solr/dovecot/conf/schema.xml # Note: solr will replace schema.xml with managed-schema if { [file exists ${prefix}/var/solr/dovecot/conf/managed-schema.orig] } { delete ${prefix}/var/solr/dovecot/conf/managed-schema.orig } move ${prefix}/var/solr/dovecot/conf/managed-schema \ ${prefix}/var/solr/dovecot/conf/managed-schema.orig # Edit in the Lucene version; see lucene-spec at http://localhost:8983/solr reinplace -E -q \ "s|()\[\[:digit:\]\]\\.\[\[:digit:\]\]\\.\[\[:digit:\]\]()|\\1${solr_version}\\2|" \ ${prefix}/var/solr/dovecot/conf/solrconfig.xml reinplace -E -q \ "s|||" \ ${prefix}/var/solr/dovecot/conf/solrconfig.xml # rspamd configuration if { ![file exists ${prefix}/var/lib/rspamd/dkim] } { xinstall -m 0750 -o _rspamd -g _rspamd -d \ ${prefix}/var/lib/rspamd/dkim } foreach f_or_d { local.d dkim_paths.map dkim_selectors.map } { install_initial_configuration ${prefix}/etc/rspamd/${f_or_d} } foreach f [list \ ${prefix}/var/lib/rspamd/dkim/${domaintld}.dkim_rsa2048.key \ ${prefix}/var/lib/rspamd/dkim/${domaintld}.dkim_ed25519.key ] { if { ![file exists ${f}] } { set f_txt [strsed ${f} {s|\.key$|.txt|}] if { [string match "*rsa2048*" ${f}] } { system -W ${prefix}/var/lib/rspamd/dkim \ "sh -c \"rspamadm dkim_keygen \ -k ${f} -s dkim_rsa2048 -t rsa -b 2048 \ -d ${domaintld} \ 1>${f_txt}\"" } elseif { [string match "*ed25519*" ${f}] } { system -W ${prefix}/var/lib/rspamd/dkim \ "sh -c \"rspamadm dkim_keygen \ -k ${f} -s dkim_ed25519 -t ed25519 \ -d ${domaintld} \ 1>${f_txt}\"" } file attributes ${f} \ -owner _rspamd -group _rspamd -permissions 0640 file attributes ${f_txt} \ -owner _rspamd -group _rspamd -permissions 0644 } } # redis configuration foreach f_or_d { redis.conf } { install_initial_configuration ${prefix}/etc/${f_or_d} } # dcc configuration foreach f_or_d { dcc_conf } { install_initial_configuration ${prefix}/etc/dcc/${f_or_d} } # logrotate configuration if { [variant_isset "logrotate"] } { foreach f_or_d { logrotate.conf logrotate.d } { install_initial_configuration ${prefix}/etc/${f_or_d} } } # TLS certificate surrogate -- certificate authority chain of trust xinstall -m 0700 -d ${tls_ca_dir}/private xinstall -m 0700 -d ${tls_ca_dir}/intermediate/private foreach f { \ openssl.cnf \ intermediate/openssl_intermediate.cnf \ } { reinplace "s|@TLS_CA_DIR@|${tls_ca_dir}|g" ${tls_ca_dir}/${f} } # CA and Intermediate CA encrypted key passphrases in ./private # CA passphrase set tls_ca_passphrase \ [correct_horse_battery_staple] set tls_ca_passphrase_fd \ [open ${tls_ca_dir}/private/passphrase.txt w 0600] puts ${tls_ca_passphrase_fd} \ ${tls_ca_passphrase} close ${tls_ca_passphrase_fd} # Intermediate CA passphrase set tls_intermediate_ca_passphrase \ [correct_horse_battery_staple] set tls_intermediate_ca_passphrase_fd \ [open ${tls_ca_dir}/intermediate/private/passphrase_intermediate.txt w 0600] puts ${tls_intermediate_ca_passphrase_fd} \ ${tls_intermediate_ca_passphrase} close ${tls_intermediate_ca_passphrase_fd} # Client certificate passphrase set tls_client_certificate_passphrase \ [correct_horse_battery_staple] set tls_client_certificate_passphrase_fd \ [open ${tls_ca_dir}/intermediate/private/passphrase_client.txt w 0600] puts ${tls_client_certificate_passphrase_fd} \ ${tls_client_certificate_passphrase} close ${tls_client_certificate_passphrase_fd} # create the chain of trust system -W ${tls_ca_dir} \ "sh < serial touch index.txt # Intermediate CA certificate openssl ca -config openssl.cnf \\ -days 730 -notext -md sha384 -extensions v3_intermediate_ca \\ -in intermediate/intermediate.csr.pem \\ -out intermediate/intermediate.cert.pem \\ -passin file:private/passphrase.txt -batch # Intermediate CA chain cat intermediate/intermediate.cert.pem ca.cert.pem \\ > intermediate/ca-chain.cert.pem # Intermediate CA chain openssl verification openssl verify -CAfile ca.cert.pem intermediate/ca-chain.cert.pem ################## # Client Certs ################## # Client certificate encrypted key openssl genpkey \\ -out intermediate/private/${fullhost}.key.pem \\ -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -aes256 \\ -pass file:intermediate/private/passphrase_client.txt chmod go-r intermediate/private/${fullhost}.key.pem # Client certificate decrypted key openssl pkey -in intermediate/private/${fullhost}.key.pem \\ -passin file:intermediate/private/passphrase_client.txt \\ -out intermediate/private/${fullhost}.key.pem.decrypted chmod go-r intermediate/private/${fullhost}.key.pem.decrypted # Client certificate CSR openssl req -config intermediate/openssl_intermediate.cnf \\ -new -sha384 \\ -key intermediate/private/${fullhost}.key.pem \\ -passin file:intermediate/private/passphrase_client.txt \\ -out intermediate/${fullhost}.csr.pem -batch # Intermediate CA initialize database echo 01 > intermediate/serial touch intermediate/index.txt # Client certificate openssl ca -config intermediate/openssl_intermediate.cnf \\ -days 375 -notext -md sha384 \\ -in intermediate/${fullhost}.csr.pem \\ -out intermediate/${fullhost}.cert.pem \\ -passin file:intermediate/private/passphrase_intermediate.txt \\ -subj '/CN=${fullhost}' -batch # Client chain openssl verification openssl verify -CAfile intermediate/ca-chain.cert.pem \\ intermediate/${fullhost}.cert.pem # Client chain of trust cat intermediate/${fullhost}.cert.pem \\ intermediate/intermediate.cert.pem ca.cert.pem \\ > intermediate/${fullhost}.chain.pem # Client certificate of the forms # @host@.@domain@.@tld@.@CERTIFICATE_SHA1@.{cert,key,chain}.pem TLS_CERTIFICATE_SURROGATE " set certificate_sha1 [exec \ openssl x509 -noout -fingerprint -sha1 -inform pem \ -in ${tls_ca_dir}/intermediate/${fullhost}.cert.pem] regsub -nocase "^sha1 Fingerprint=" ${certificate_sha1} "" certificate_sha1 set certificate_sha1 [string tolower [strsed ${certificate_sha1} "g|:||"]] xinstall -m 0600 \ ${tls_ca_dir}/intermediate/private/${fullhost}.key.pem.decrypted \ ${certificates_dir}/private/${fullhost}.${certificate_sha1}.key.pem.decrypted xinstall -m 0600 \ ${tls_ca_dir}/intermediate/private/${fullhost}.key.pem \ ${certificates_dir}/private/${fullhost}.${certificate_sha1}.key.pem xinstall -m 0600 \ ${tls_ca_dir}/intermediate/private/passphrase_client.txt \ ${certificates_dir}/private/${fullhost}.${certificate_sha1}.key.passphrase xinstall -m 0644 \ ${tls_ca_dir}/intermediate/${fullhost}.cert.pem \ ${certificates_dir}/${fullhost}.${certificate_sha1}.cert.pem xinstall -m 0644 \ ${tls_ca_dir}/intermediate/${fullhost}.chain.pem \ ${certificates_dir}/${fullhost}.${certificate_sha1}.chain.pem # configure all template files with local settings set d_or_f_templates { \ postfix \ dovecot \ rspamd \ redis.conf \ } if { [variant_isset "logrotate"] } { append d_or_f_templates { \ logrotate.conf \ logrotate.d \ } } foreach d_or_f ${d_or_f_templates} { fs-traverse f ${prefix}/etc/${d_or_f} { if { [file isfile ${f}] && ![string match ".macports" ${f}] && [string match "text/*" \ [lindex [exec /usr/bin/file --mime-type ${f}] end]] } then { foreach cmd [list \ "s|@PREFIX@|${prefix}|g" \ "s|@host@.@domain@.@tld@|${fullhost}|g" \ "s|@domain@.@tld@|${domaintld}|g" \ "s|@host@|${host}|g" \ "s|@domain@|${domain}|g" \ "s|@tld@|${tld}|g" \ "s|@HOST@.@DOMAIN@.@TLD@|${FULLHOST}|g" \ "s|@DOMAIN@.@TLD@|${DOMAINTLD}|g" \ "s|@HOST@|${HOST}|g" \ "s|@DOMAIN@|${DOMAIN}|g" \ "s|@TLD@|${TLD}|g" \ "s|@RSPAMD_CONTROL_PASSWORD@|${rspamd_control_password}|g" \ "s|@RSPAMD_CONTROL_PASSWORD_HASH@|${rspamd_control_password_hash}|g" \ "s|@CERTIFICATE_SHA1@|${certificate_sha1}|g" \ "s|@RELAYHOST@|${relayhost}|g" \ ] { reinplace -q ${cmd} ${f} } } } } # postfix relay host and password surrogate system -W ${prefix}/etc/postfix/sasl "postmap passwd" # postfix permissions # system -W ${prefix}/etc/postfix "postfix set-permissions" # dovecot sieve functions # dovecot must be built with `--with-lucene` for sievec to work here if { ![catch {set result [registry_active dovecot]}] && [string match "*solr*" [lindex [lindex ${result} 0] 3]] } { foreach d { sieve sieve-before.d sieve-afer.d } { foreach f [glob -nocomplain ${prefix}/etc/dovecot/${d}/*.sieve] { system -W ${prefix}/etc/dovecot/${d} "sievec ${f}" } } } else { ui_msg "dovecot plugin 'fts_lucene' not installed. Please install: sudo port -pN install dovecot +[join ${dovecot_required_variants} +] and rerun `sudo port install ${name}`. Ensure that the sieve scripts in ${prefix}/etc/dovecot/sieve*/*.sieve are compiled with sievec. " } # PAM authentication if { ![file exists /etc/pam.d/smtp] } { xinstall -m 0644 ${prefix}/etc/postfix/etc/pam.d/smtp /etc/pam.d/ } if { ![file exists /etc/pam.d/imap] } { xinstall -m 0644 ${prefix}/etc/dovecot/etc/pam.d/imap /etc/pam.d/ } # TLS PFS if { ![file exists ${prefix}/var/lib/postfix/dh2048.pem] } { system -W ${prefix}/var/lib/postfix "sudo -u _postfix openssl dhparam -out dh2048.pem 2048" } if { ![file exists ${prefix}/etc/dovecot/dh2048.pem] } { # create a shorter, faster DH parameter file for the default installation system -W ${prefix}/etc/dovecot "openssl dhparam -out dh2048.pem 2048" } # mail group membership # dscacheutil -q group -a name mail foreach u { _postfix _dovecot _dovenull _rspamd } { system "dseditgroup -o edit -a ${u} -t user mail" } } startupitem.create yes startupitems \ name ${name} \ start { "port load clamav-server" "port load apache-solr8" "port load redis" "port load dcc" "port load postfix" "port load dovecot" "port load rspamd" } \ stop { "port unload apache-solr8" "port unload dcc" "port unload postfix" "port unload dovecot" "port unload rspamd" } \ restart { "port reload apache-solr8" "port reload redis" "port reload dcc" "port unload postfix" "sleep 1" "port load postfix" "port unload dovecot" "sleep 1" "port load dovecot" "port reload rspamd" } if { [variant_isset "logrotate"] } { startupitems-append \ name ${name}.logrotate \ executable ${prefix}/sbin/logrotate } notes "A mail server is a complex, interdependent set of tools that must \ all be configured correctly to provide secure, reliable email. Users must reconfigure this installation for their own system, network, \ and security model specifics by editing all necessary files and checking \ file permissions. A subset of these settings are visible in the files: port contents mail-server port file mail-server Full deployment also requires a working DNS configuration on both the LAN \ and the internet, including SPF and DKIM records, trusted TLS certificates, \ port forwarding, possibly a mail replay, and more. Postfix and dovecot must be installed with these variants: sudo port -pN install postfix +[join ${postfix_required_variants} +] sudo port -pN install dovecot +[join ${dovecot_required_variants} +] \[+apns] These are the locations and network settings for the default configuration: MTA (postfix): ${prefix}/etc/postfix/main.cf ${prefix}/etc/postfix/master.cf ports: smtp/tcp (25), submission/tcp (587) MDA (dovecot): ${prefix}/etc/dovecot/dovecot.conf ${prefix}/etc/dovecot/conf.d/* port: imaps/tcp (993) FTS (solr): http://localhost:8983/ Milter (rspamd): ${prefix}/etc/rspamd/rspamd.conf ${prefix}/etc/rspamd/local.d/* A default Rspamd controller password and its hash appear in the files: ${prefix}/etc/dovecot/sieve/train-spam.sh ${prefix}/etc/dovecot/sieve/train-ham.sh ${prefix}/etc/rspamd/local.d/worker-controller.inc Rspamd controller: http://localhost:11334/ Spam/Ham training (default behavior): Move/Copy email to the folders Spam_train or Notspam_train. The configuration also includes a surrogate TLS certificate and DKIM settings \ that must be changed before deployment. TLS: ${prefix}/etc/certificates DKIM: ${prefix}/var/lib/rspamd/dkim The ports dns-server provide necessary DNS service on the LAN; variant \ +logrotate provides log rotation capabilities: sudo port install dns-server sudo port install mail-server +logrotate This port assume indepedent installation and management of DNS and \ log rotation; mail-server includes example logrotate configuration files \ and a logroate launchdaemon. The port's launch daemon controls launching for each of the dependendent \ services. These may be controlled independently, e.g. sudo port load clamav-server sudo port load apache-solr8 sudo port load redis sudo port load dcc sudo port load postfix sudo port load dovecot sudo port load rspamd and if installed independently, sudo port load dns-server sudo port load logrotate TLS certificate updates must be included in mail-server dovecot's \ conf.d/10-ssl.conf, postfix's master.cf, and, if installed, \ calendar-contacts-server's proxy nginx.conf. Instructions are \ included as comments in: sudo vi ${prefix}/etc/dovecot/conf.d/10-ssl.conf sudo vi ${prefix}/etc/postfix/main.cf sudo vi \\ ${prefix}/var/calendarserver/Library/CalendarServer/etc/nginx.conf References: * http://www.postfix.org/documentation.html * https://wiki.dovecot.org/ * https://www.rspamd.com/doc/index.html * https://www.c0ffee.net/blog/mail-server-guide/ * _The Book of Postfix_, by Patrick Koetter and Ralf Hildebrandt Known issues: * The Postfix service does not reliably start after reboot, \ presumably due to an issue with launchd. A workaround \ after rebooting is to issue the commands: sudo port unload postfix ; sleep 5 ; sudo port load postfix" if { [variant_isset "initialize_always"] } { if {[exists notes]} { # leave a blank line after the existing notes notes-append "" } notes-append \ "The variant +initialize_always is set, which initializes \ all configuration files. Please disable this variant for \ working deployments." } livecheck.type none