Date
Updated
Kernel
7.3.4-arch1-1 #1 SMP PREEMPT_DYNAMIC | x86_64 GNU/Linux
OS
Arch Linux
These are my installation notes for a full mail server. I don't explain a lot here but if it still helps you in some way then that's just fine.
SMTP submission authentication is handled by Dovecot/Exim and standard user accounts will work; just use the local part of a user account email address ie. 'foo' (minus the quotes) instead of 'foo@mydomain.tld' (minus the quotes) for mail client configuration.
# pacman -Syu exim dovecot pigeonhole spamassassin certbot grc# mkdir -m 0750 /etc/mail/certs# certbot -d mydomain.tld certonly <--- choose 'standalone web server' and temporarily open port 80 on the router/firewall# cp /etc/letsencrypt/archive/mydomain.tld/fullchain1.pem /etc/mail/certs# cp /etc/letsencrypt/archive/mydomain.tld/privkey1.pem /etc/mail/certs # chown -R root:exim /etc/mail/certs# chmod 0640 /etc/mail/certs/privkey1.pem# mkdir -m 0750 /etc/mail/keys# cd /etc/mail/keys# openssl genrsa -out dkim_private.pem 4096# openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem <--- add contents of dkim_public.pem to DNS# chown -R root:exim /etc/mail/keys# chmod 0640 root:exim /etc/mail/keys/dkim_private.pem# mkdir -m 0750 /var/log/dovecot # touch /var/log/dovecot/dovecot.log # chown -R dovecot:root /var/log/dovecot # chmod 0640 /var/log/dovecot/dovecot.log# mkdir -m 0750 /var/log/spamassassin # touch /var/log/spamassassin/spamd.log # chown -R spamd:root /var/log/spamassassin/ # chmod 0640 /var/log/spamassassin/spamd.log
Run sa-update. Create /etc/systemd/system/spamassassin.service.d/override.conf which contains the information below. Run systemctl daemon-reload and then systemctl restart spamassassin.
[Unit]Description=SpamAssassin DaemonAfter=network.target[Service]ExecStart=ExecStart=/usr/bin/vendor_perl/spamd -x -u spamd --max-children 5 --helper-home-dir --syslog=/var/log/spamassassin/spamd.logStandardOutput=nullStandardError=nullRestart=always
In /etc/mail/spamassassin/local.cf:
skip_rbl_checks 0trusted_networks 192.168.0.0/24#bayes_path /var/lib/spamassassin/.spamassassinuse_bayes 1bayes_auto_learn 1bayes_file_mode 0660add_header spam Flag _YESNOCAPS_dns_query_restriction deny multi.uribl.comdns_query_restriction deny dnsblock_list.dnswl.orgdns_query_restriction deny bl.score.senderscore.comdns_query_restriction deny sa-trusted.bondedsender.orgdns_query_restriction deny sa-accredit.habeas.comdns_query_restriction deny list.dnswl.orgdns_query_restriction deny sorbs.netdns_query_restriction deny URIBLdns_query_restriction deny DNSWLdns_query_restriction deny SURBLclear_report_templatereport "_TESTSSCORES(, )_"required_score 4.5whitelist_from contact@somedomain.tldblacklist_from *@mentalmarketing.tld
In /etc/mail/exim.conf:
####################################################################### EXIM 4 RUNTIME CONFIGURATION #######################################################################primary_hostname = mydomain.tldsmtp_banner = $smtp_active_hostname ESMTP $tod_full.#log_selector = +alldisable_ipv6 = truelocal_interfaces = 127.0.0.1 : 192.168.0.10system_filter = /etc/mail/main_filter <--- File must begin with: # Exim filtersystem_filter_user = eximkeep_environment =domainlist local_domains = @ : superhost.tld : anotherone.tlddomainlist relay_to_domains =hostlist relay_from_hosts = 127.0.0.1acl_smtp_connect = acl_check_connacl_smtp_rcpt = acl_check_rcptacl_smtp_data = acl_check_datatls_advertise_hosts = *auth_advertise_hosts = ${if eq {$tls_cipher}{}{}{*}}tls_certificate = /etc/mail/certs/fullchain1.pemtls_privatekey = /etc/mail/certs/privkey1.pemdaemon_smtp_ports = 25 : 587spamd_address = 127.0.0.1 783qualify_domain = mydomain.tldexim_user = eximexim_group = eximnever_users = roothost_lookup = *rfc1413_query_timeout = 0signore_bounce_errors_after = 5dtimeout_frozen_after = 7d####################################################################### ACL CONFIGURATION ## Specifies access control lists for incoming SMTP mail #######################################################################begin aclacl_check_conn:drop hosts = /etc/mail/host_rejectmessage = Connection terminated.deny condition = ${if eq{$received_port}{587}}!hosts = localhost : 192.168.0.0/24message = Submission port access denied for $sender_host_address.acceptacl_check_rcpt:accept hosts = :control = dkim_disable_verifydeny message = Restricted characters in addressdomains = +local_domainslocal_parts = ^[.] : ^.*[@%!/|]deny message = Restricted characters in addressdomains = !+local_domainslocal_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./accept local_parts = postmaster : abuse : rootdomains = +local_domains#require verify = senderaccept hosts = +relay_from_hostscontrol = submissioncontrol = dkim_disable_verifyaccept authenticated = *control = submissioncontrol = dkim_disable_verifydenymessage = No rDNS found.condition = ${if eq{$host_lookup_failed} {1} {1}{0}}require message = relay not permitteddomains = +local_domains : +relay_to_domainsrequire verify = recipientdrop hosts = /etc/mail/host_rejectmessage = Connection refused.denysenders = /etc/mail/blocked_sendersmessage = Mail rejected.denymessage = Access denied. $sender_host_address found on zen.spamhaus.org.dnslists = zen.spamhaus.orgacceptacl_check_data:# Do not scan messages larger than 500KBacceptcondition = ${if >{$message_size}{500000} {1}}# # Add X-Spam headers and scan via spamdwarnmessage = X-Spam-Score: $spam_scorespam = spamd:truewarnmessage = X-Spam-Report: $spam_reportspam = spamd:truedenymessage = Spamtastic.spam = spamd:truecondition = ${if >={$spam_score_int}{43}{1}{0}}accept####################################################################### ROUTERS CONFIGURATION ## Specifies how addresses are handled ######################################################################## THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! ## An address is passed to each router in turn until it is accepted. #######################################################################begin routersdnslookup:driver = dnslookupdomains = ! +local_domainstransport = remote_smtpignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1no_moresystem_aliases:driver = redirectallow_failallow_deferdata = ${lookup{$local_part}lsearch{/etc/mail/aliases}}file_transport = address_filepipe_transport = address_pipeuserforward:driver = redirectcheck_local_userfile = $home/.forwardno_verifyno_expncheck_ancestorfile_transport = address_filepipe_transport = address_pipereply_transport = address_replylocaluser:debug_print = “R: local_user for $local_part@$domain”driver = acceptdomains = +local_domainscheck_local_userlocal_parts = ! roottransport = dovecot_lmtpcannot_route_message = Unknown user####################################################################### TRANSPORTS CONFIGURATION ######################################################################## ORDER DOES NOT MATTER ## Only one appropriate transport is called for each delivery. ######################################################################## A transport is used only when referenced from a router that successfully# handles an address.begin transportsremote_smtp:driver = smtpport = 25headers_remove = received : X-Spam-Score : X-Spam-Reportdkim_domain = mydomain.tlddkim_selector = defaultdkim_private_key = /etc/mail/keys/dkim_private.pemdkim_hash = sha256dkim_canon = relaxeddkim_strict = 1dkim_timestamps = 864000internal_smtp:driver = smtpdovecot_lmtp:driver = lmtpsocket = /var/run/dovecot/lmtpbatch_max = 200rcpt_include_affixesaddress_pipe:driver = pipereturn_outputaddress_file:driver = appendfiledelivery_date_addenvelope_to_addreturn_path_addaddress_reply:driver = autoreply####################################################################### RETRY CONFIGURATION #######################################################################begin retry# Address or Domain Error Retries# ----------------- ----- -------* * F,2h,15m; G,16h,1h,1.5; F,4d,6h####################################################################### REWRITE CONFIGURATION ######################################################################## There are no rewriting specifications in this default configuration file.begin rewrite####################################################################### AUTHENTICATION CONFIGURATION #######################################################################begin authenticatorsdovecot_plain:driver = dovecotpublic_name = LOGINserver_socket = /var/run/dovecot/exim-authserver_set_id = $auth1fixed_plain:driver = plaintextpublic_name = PLAINclient_send = ^myusername^mypassword# End of Exim configuration file
In /etc/dovecot/dovecot.conf:
## Dovecot configuration file# Dovecot configuration version. This must be the first setting in the# configuration file. It specifies the configuration syntax, the used setting# names and the expected default values.dovecot_config_version = 2.4.5# Dovecot storage file format version. It specifies the oldest Dovecot version# that must be able to read files written by this Dovecot instance. The# intention is that when upgrading Dovecot cluster, this setting is first kept# as the old Dovecot version. Once the cluster is fully upgraded to a new# version and there is no intention to rollback to the old version anymore,# this version number can be increased.dovecot_storage_version = 2.4.5# The configuration below is a minimal configuration file using system user authentication.# See https://doc.dovecot.org/latest/core/config/quick.html!include_try conf.d/*.conf# Enable wanted protocols:protocols {imap = yeslmtp = yes}mail_driver = maildirmail_path = ~/Maildirservice imap-login {inet_listener imap {port = 0}inet_listener imaps {port = 993ssl = yes}}auth_failure_delay = 12 secsauth_mechanisms = plain loginprotocol lmtp {mail_plugins = sieveauth_username_format = %{user | username}}recipient_delimiter = + -log_path = /var/log/dovecot/dovecot.logservice auth {unix_listener exim-auth {mode = 0660user = eximgroup = exim}}service lmtp {unix_listener /var/run/dovecot/exim-lmtp {mode = 0600user = eximgroup = exim}}namespace inbox {inbox = yesseparator = /}# Authenticate as system users:passdb pam {}userdb passwd {}ssl_server {cert_file = /etc/letsencrypt/live/mydomain.tld/fullchain.pemkey_file = /etc/letsencrypt/live/mydomain.tld/privkey.pem}
In /home/foo/.dovecot.sieve:
require ["fileinto", "envelope", "regex", "duplicate"];## spam filing blockif allof ( not header :matches "X-Spam-Score" "-*",header :regex "X-Spam-Score" "^4\.4$" ) {fileinto "Spam";stop;}# Continue as/if necessaryif address :is "from" "logs@mydomain.tld" {fileinto "Logs";stop;}# All other mail should end up in the INBOX