Setup Email Server From Scratch On FreeBSD #2 - 10 Blocking Spam With Postfix
09 Create Virtual Domains <- Intro -> 11 SpamAssassin
We believe in data independence, and support others who want data independence.
This tutorial is complete 2025-08-14 except there is no page for setting up postscreen.
This is version 2 and everthing works.
############################## # Blocking Spam With Postfix # ##############################
Change your smtpd banner to provide less information about your mail service
nano /usr/local/etc/postfix/main.cf
--- change this ---
smtpd_banner = $myhostname ESMTP
Reject email from hosts with invalid A Record or no PTR Record, some or none of these. Use either reject_unknown_client_hostname or reject_unknown_reverse_client_hostname, not both.
reject_unknown_sender_domain : no MX or A Record
reject_unknown_reverse_client_hostname : NO IP -> NAME (weaker doesn't check for match, just if it exists)
reject_unknown_client_hostname : Must have both A and PTR and both must map to IP (strong)
Some spam bot don't provide a compliant HELO ELHO greeting, so these can be bounced, dropped, or rejected.
nano /usr/local/etc/postfix/main.cf
--- edit near bottom of file ---
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
smtpd_sender_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unknown_sender_domain
reject_unknown_reverse_client_hostname
# reject_unknown_client_hostname
# Reject invalid HELO/EHLO
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks
permit_sasl_authenticated
check_helo_access hash:/usr/local/etc/postfix/helo_access
reject_invalid_helo_hostname
reject_non_fqdn_helo_hostname
reject_unknown_helo_hostname
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:opendkim/opendkim.sock,unix:opendmarc/opendmarc.sock
non_smtpd_milters = $smtpd_milters
# Pass bounces to milters so bounce messages also get DKIM signed are are not rejected
internal_mail_filter_classes = bounce
Setup whitelist for servers that do not need to conform to helo
nano /usr/local/etc/postfix/helo_access
# whitelist legitimate servers that don't conform to helo
optimus-webapi-prod-2.localdomain OK
va-massmail-02.rakutenmarketing.com OK
goodhost1.domain1.com OK
goodhost1.domain2.com OK
postmap /usr/local/etc/postfix/helo_access
service postfix restart
service postfix status
Enable Greylisting in Postfix
Quote from linuxbabe "As required by the SMTP protocol, any legitimate SMTP client must be able to re-send email if delivery fails. (By default, Postfix is configured to resend failed emails many times before it informs the sender that the message could not be delivered.) Many spammers usually just send once and would not retry."
pkg install postgrey
nano /etc/rc.conf
sysrc postgrey_enable="YES"
postgrey_flags=" --inet=127.0.0.1:10023 --delay=1 --greylist-text='4.7.1 Greylisted'"
service postgrey start
Postgrey will generate a warning on startup but it will start.
Attempt to call undefined import method with arguments ("1.05") via package "IO::Multiplex"
... at /usr/local/lib/perl5/site_perl/Net/Server/Multiplex.pm line 26.
perldoc -m IO::Multiplex | grep VERSION
our $VERSION = '1.16';
To get rid of the warning remove the version number.
nano /usr/local/lib/perl5/site_perl/Net/Server/Multiplex.pm
#@eval { require IO::Multiplex; import IO::Multiplex 1.05; };
@eval { require IO::Multiplex; import IO::Multiplex; };
$@ && warn "Module IO::Multiplex is required for Multiplex.";
service postgrey restart
Stopping postgrey.
Waiting for PIDS: 92489.
Starting postgrey.
Check that postgrey is listening on port 10023
sockstat -l | grep 10023
postgrey perl 92591 5 tcp6 ::1:10023 *:*
postgrey perl 92591 6 tcp4 127.0.0.1:10023 *:*
Add check_policy_service inet:127.0.0.1:10023 to smtpd_recipient_restrictions
nano /usr/local/etc/postfix/main.cf
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf,
check_policy_service inet:127.0.0.1:10023
To prevent postgrey from slowing down legitimate mails, use to 2 DNS entries so the mail server will first try the entry with priority 0 then after 1 second try the entry with priority 10, eg a resend and less likely to be spam.
To prevent greylisting delay add 2 mx records to your DNS, like this.
MX smtp.okbsd.com.com 0
MX mail.okbsd.com.com 10
For the other virtual domains do the same.
MX smtp.coragarden.com.com 0
MX mail.coragarden.com.com 10
service postfix restart
View postgrey logs, see what is being blocked, to see if new entries need to be added to whitelist.
tail -200 -f /var/log/maillog | grep postgrey
- or -
grep postgrey /var/log/maillog
Postgrey Whitelist - You can add client to postgrey';s default whitelist, the files are located in /usr/local/etc/postfix.
Clients File
/usr/local/etc/postfix/postgrey_whitelist_clients
Recipients File
/usr/local/etc/postfix/postgrey_whitelist_recipients
If modifying Postgrey whitelists restart postgrey.
service postgrey restart
Real Time Blacklists and Whitelists - these tell postfix to contact real time blacklist servers and block email if the client is on the blacklist, or conversely allow if on the whitelist.
Spamhaus requires domains the register using thier postmaster@domain.tld email address so let's do this now. Go to...
https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account/
https://www.spamhaus.com/product/data-query-service/#
A single DQS key can be used with multiple mail servers.
Postfix spamhaus filtering can be disabled, if enabled using Spamassasin...
https://docs.spamhaus.com/datasets/docs/source/40-real-world-usage/MTAs/020-Postfix.html
Update, I haven't found any advantage or gotten DQS service to work, but the settings here for spamhaus show 'all green' correctly configured.
nano /usr/local/etc/postfix/main.cf
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf,
check_policy_service inet:127.0.0.1:10023,
check_client_access hash:/usr/local/etc/postfix/rbl_override,
reject_rhsbl_helo dbl.spamhaus.org,
reject_rhsbl_reverse_client dbl.spamhaus.org,
reject_rhsbl_sender dbl.spamhaus.org,
permit_dnswl_client list.dnswl.org=127.0.[0..255].[1..3],
permit_dnswl_client swl.spamhaus.org,
reject_rbl_client zen.spamhaus.org
# You can override the blacklists by adding domains to the rbl_override file.
nano /usr/local/etc/postfix/rbl_override
domain1.com OK // ignore rbl for domain1.com
domain2.com OK // ignore rbl for domain2.com
postmap /usr/local/etc/postfix/rbl_override
# Using Public Whitelist to Reduce False Positive / from linuxbabe
# You can use whitelists but a dns whitelist is enabled in postscreen and a spamhaus can't have the same record in the whitelist and blacklist so the whitelist is not needed here.
# Postfix Log Reports
pkg install pflogsumm mutt
# test it
pflogsumm /var/log/maillog -d today /var/log/maillog
# Setup a crontab to send a report at 12:30am. Initially I used maillog but it rotates at 12am so yesterday has been rotated by the time cron is run. This cron reads the yesterdays compressed log and pipes that to pflogsumm to send the report.
crontab -e
30 0 * * * bzcat /var/log/maillog.0.bz2 | pflogsumm -d yesterday | /usr/local/bin/mutt -s "Postfix log summary" -- postmaster@okbsd.com
# Make sure you are not an open relay
nano /usr/local/etc/postfix/main.cf
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
# We setup DMARC in a prevous page, but make sure your myhostname in postfix/main.cf is included in TrustedAuthservIDs, mine is smtp.okbsd.com
nano /usr/local/etc/mail/opendmarc.conf
TrustedAuthservIDs localhost,smtp.okbsd.com,mail.okbsd.com
nano /usr/local/etc/mail/ignore.hosts
127.0.0.1
147.135.65.9
2604:2dc0:200:187::1
::1
localhost
smtp.okbsd.com
# Dont DKIM check your own hosts
nano /usr/local/etc/mail/trustedhosts
127.0.0.1
localhost
147.135.37.135
2604:2dc0:200:187::1
*.okbsd.com
okbsd.com
*.coragarden.com
coragarden.com
service postfix restart
# Enable PostScreen in Postfix Prefilter
# To conserve resource it is better to block certain types of email before going through spam and virus filters in postfix. This is what postgrey does, filters and blocks or drops the email before more resource intensive process are triggered.
# Check that everything works.
# If everything works back it up with tar like we did before.
09 Create Virtual Domains <- Intro -> 11 SpamAssassin
##################### # Next SpamAssassin # #####################