Configure a firewall
There is an older article for use with IPFW. I no longer use IPFW in favor of PF, which I recommend that you use as well. The rest of this article assumes the use of PF.
The <spamd> table referenced in this document refers to OpenBSD's spamd application, found in /usr/ports/mail/spamd on FreeBSD. I have spamd pre-loaded to automatically block all of China, Korea, and the Spamhaus DNSBL.
Example PF config
# Macros: define common values, so they can be referenced and changed easily.
ext_if="em0"    # actual external interface name i.e., dc0
int_if="em1"
loop_if="lo0"
int_net="127.0.0.1/8"
loop_net="127.0.0.1/8"
ext_addr="72.29.111.130"
ext_net ="72.29.111.128/27" 
mail_ports = "{ 25, 110, 143, 465, 587, 993, 995 }" 
It would probably be a good idea to change the IP and interface names here :)
# Tables: similar to macros, but more flexible for many addresses.
# mail_servers are IPs which we run mail servers on.
table <mail_servers> { 72.29.111.130 72.29.111.133 72.29.111.141 72.29.111.149 }
In this example, my Mail Toaster is running inside a jail on .133. However, I have opened up port 25 on two more IPs, .130 and .149. I do this because I noticed that some spammers were scanning IP ranges for listeners on port 25. So I gave them one that will catch them scanning from the bottom up or top down. More on that later...
# the <spamd> table is where we put those who offend us
table <spamd> persist
# a way to override spamd, useful since I have all of china and korea in <spamd>
table <spamd-white>  persist file "/var/mail/whitelist.txt"
table <no_mail>      { 72.29.111.130 72.29.111.149 }
<no_mail> is IPs which nobody has any business connecting to. Combined with my script that auto-blocks anyone who connects to it, this will catch anyone scanning blocks of IPs for open ports. -- muhahhaha
# Queueing: rule-based bandwidth control.
altq on $ext_if bandwidth 10Mb cbq queue { q_default q_mail }
  queue q_default bandwidth 9Mb cbq(default)
  queue q_mail bandwidth 1Mb { q_mail_windows }
  queue q_mail_windows bandwidth 56Kb
Here I limit how much of my 100Mb can be utilized. I reserve 1Mb for email, and an even smaller 56Kb email queue Windows email senders. More on that later...
# Translation: specify how addresses are to be mapped or redirected.
# spamd-setup puts addresses to be redirected into table <spamd>.
no rdr on { lo0, lo1 } from any to any
rdr inet proto tcp from <spamd> to any port smtp -> $ext_addr port 8025
# allow traffic to spamd
pass in quick proto tcp from any to $ext_addr port 8025 keep state
# block probes to port 25
pass in quick on $ext_if proto tcp from any to <no_mail> port smtp \
        synproxy state \
        (max-src-conn-rate 1/60, overload <spamd> flush global)
This rule catches anyone who makes more than 1 connect in 60 seconds to the IPs in my <no_mail> list. My readings on the openbsd-misc list led me to conclude that there is not yet an option to do this on the first connect attempt, which is really what I wanted. Hence the reason for writing a script to do it...
# limit port 25 bandwidth from Windows hosts
pass in quick proto tcp from any os "Windows" to <mail_servers> port smtp \
        keep state queue q_mail_windows
Since bot nets of hijacked Windows computers are a significant spam source, we should be able to use that knowledge to prevent spam. But, I do get legit email from Windows servers, I can't just block them entirely. But I can slow them down. This will do for now....
# allow email connections
pass in quick proto tcp from any to <mail_servers> port $mail_ports \
        keep state queue q_mail 
And the rest of the mail traffic gets dumped into the normal mail queue.