I was asked recently to find an email solution for a new marketing firm. The solution specifically, was for the problem of outbound IP binding. That is what IP address email is sent from. If youâre providing email outsourcing for multiple clients, itâs important to keep each client on itâs own IP(s) so one being blacklisted wonât affect another.
Itâs a simple matter to add IP addresses to a server for the purposes of listening, but to tell a mail server to send from a particular IP(s) (and not just the default IP) can be a pit tricker. Depending on the resources available to you though, this option really isnât hard. We started by looking at Qmail, as itâs a popular choice, but we ran into a number of problems applying a patch to allow it to dynamically bind to an IP per outgoing email sender domain. In the end, I built a solution using multiple Postfix instances, that each bind to the appropriate IP. Youâre going to end up with:
smtp1.domain.com
smtp2.domain.com
etc.
The first thing youâll need is a working server. Thatâs well beyond the scope of this, but for the record I sandbox in VMWare Server using CentOS 5, with MySQL, Apache, VIM, compiling tools and so on. Second thing youâll need is a working Postfix installation. This took me a long time at first, due solely to a formatting error step 4, below. That was very frustratingâ¦. but if you learn from my mistakes youâll have an easier time. Trick is to format the make command just right.
1. Grab the Postfix source, and untar. I used the guide here for the install, itâs got all the basics that you need. You should really follow along in that, and turn here if itâs instructions are a little spartan.
2. Youâll need to ensure MySQL and MySQL-devel are installed. My finished Postfix instances didnât use them (because they werenât receiving mail, just sending), but I couldnât see how to compile without the MySQL step. I had to reboot after installing MySQL-devel.
3. Run:
make -f Makefile.init makefiles \
âCCARGS=-DHAS_MYSQL -I/usr/include/mysqlâ \
âAUXLIBS=-L/usr/lib/mysql/ -lmysqlclient -lz -lmâ
make
4.If steps 3 throws errors, youâre going to have to hunt for a solution. Once successful, run the following. This will build makefiles, using the following directories for data, config, and queues. Adjust as necessary. (Bear in mind, multiple Postfixes only need a single set of binaries, but multiple conf and spool folders):
make makefiles CCARGS=â-DDEF_CONFIG_DIR=\â/etc/postfix1\â -DDEF_DATA_DIR=\â/var/lib/postfix\â -DDEF_QUEUE_DIR=\â/var/spool/postfix1\ââ
make
5. If step 4 was a success, you just cut 4+ hours out of my initial setup time. Congrats. Now you need to create some users and groups. I use Vim to edit the conf files. If you donât know what the following does, best to check up on users and groups principles.
vim /etc/passwd:
[insert]postfix:*:12345:12345:postfix:/no/where:/no/shellvim /etc/group:
[insert]postfix:*:12345:
[insert]postdrop:*:54321:
5. Now you get to install! Lovely. The default options were fine for me all the way through (this is dependent on the makefiles we made earlier).
make install
6. Youâll need to add a hostname (or two?) at this stage, as Postfix wants a hostname, not an IP when you configure it in the following steps. Again, I use Vim, and obviously use your own IP here. You may want to use smtp1.domain.com, or whatever else:
vim /etc/hosts
[insert]192.168.0.1host.domain.com
7.Now you need to configure main.cf with the default minimum options. Configure master.cf with default options as well. (The hostname you configure Postfix with is the one you just entered into the hosts file). Note that this scenario has you binding Postfix to different IPs, so the advise to comment out a line in master.cf (if sending only) does NOT apply. Also, add the IP you wish to bind to (mail will come FROM this IP), to main.cf:
smtp_bind_address = 192.168.0.1
8. Start that sucker:
postfix -c /etc/postfix1 start
Once thatâs up and running and youâve tested it (also a good time to check the SPF records of your domains), you can go get yourself a beer. The hard part is over.Youâll also need to create a startup script for that Postfix instance. See below for a sample.
Now you can create any number of additional Postfix instances quite simply. I used the guide here, andIâm pasting below my stripped down version again (for my own records, more than anything).
9. Copy the conf files to a new directory:
cp -rp /etc/postfix1 /etc/postfix2
10. Adjust the new conf to look at a new spool directory, which you will need to create. Then have Postfix check things and create files as necessary:
vim /etc/postfix2/main.cf
[edit]queue_directory = /var/spool/postfix2mkdir /var/spool/postfix2
postfix -c /etc/postfix2 check
11. Edit the conf of the original Postfix instance to see this new set of conf files, so the Postfix daemon will load them as well:
vim /etc/postfix1/main.cf
[insert]alternate_config_directories = /etc/postfix-out
12. Now, edit the new conf file again, to adjust the hostname and the IP itâs going to bind to, and youâre just about done.
vim /etc/postfix-out/main.cf
[edit]myhostname = smtp3.domain.com
[edit]smtp_bind_address = 192.168.0.2
13. Now youâll need to create a new startup script for the new instance. Hereâs mine, for CentOS/RedHat. It assumes that Postfix binaries have been installed with the defaults from the install and any instance specific folders (conf, and spool) are âpostfix2â³. You can just run a find and replace to adjust the postfix2 path to postfix3 (or to postfix1, if this is your first startup script), and so on.
#!/bin/sh
#
# postfix2
# Postfix second instance for Redhat Linux and CentOS
# description: Postfix is a marvelous SMTP server.# Source function library.
. /etc/rc.d/init.d/functions# Source networking configuration.
. /etc/sysconfig/network# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0[ -x /usr/sbin/postfix ] || exit 0
[ -d /etc/postfix2 ] || exit 0
[ -d /var/spool/postfix2 ] || exit 0RETVAL=0
start() {
# Start daemons.
echo -n âStarting postfix2: â
if [ ! -e /var/spool/postfix2/etc/resolv.conf ]; then
cp -f /etc/resolv.conf /var/spool/postfix2/etc
fi
/usr/sbin/postfix -c /etc/postfix2 start 2>/dev/null 1>&2 && success || failure
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/postfix2
echo
return $RETVAL
}stop() {
# Stop daemons.
echo -n âShutting down postfix2: â
/usr/sbin/postfix -c /etc/postfix2 stop 2>/dev/null 1>&2 && success || failure
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/postfix2
echo
return $RETVAL
}reload() {
echo -n âReloading postfix2: â
/usr/sbin/postfix -c /etc/postfix2 reload 2>/dev/null 1>&2 && success || failure
RETVAL=$?
echo
return $RETVAL
}abort() {
/usr/sbin/postfix -c /etc/postfix2 abort 2>/dev/null 1>&2 && success || failure
return $?
}flush() {
/usr/sbin/postfix -c /etc/postfix2 flush 2>/dev/null 1>&2 && success || failure
return $?
}check() {
/usr/sbin/postfix -c /etc/postfix2 check 2>/dev/null 1>&2 && success || failure
return $?
}restart() {
stop
start
}# See how we were called.
case â$1â³ in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
reload)
reload
;;
abort)
abort
;;
flush)
flush
;;
check)
check
;;
status)
status master
;;
condrestart)
[ -f /var/lock/subsys/postfix2 ] && restart || :
;;
*)
echo âUsage: postfix2 {start|stop|restart|reload|abort|flush|check|status|condrestart}â
exit 1
esacexit $?
14. You can start your new instance with:
postfix -c /etc/postfix2 start
15. Test again mate!
16. Once thatâs done, youâre gold. You can repeat steps 9 â 15 for additional Postfix instances.
Bonus: I use PHPlist for subscriptions and mailing. To configure PHPlist to send using a particular SMTP server, look for this configuration directive (near the end of config.php). Any number of PHPList instances can now be configured to use the appropriate SMTP servers, keeping each one separate from the other, and passing SPF records and keeping spam-rule friendly.
define(âPHPMAILERHOSTâ,âhost.domain.comâ);
[...] http://www.jpuddy.net/2008/05/19/how-to-email-from-specific-ips-using-linux-and-postfix/ [...]
Very nice article mate, focused and on the subject, thanks!
In Step 4
make makefiles CCARGS=â-DDEF_CONFIG_DIR=\â/etc/postfix1\â -DDEF_DATA_DIR=\â/var/lib/postfix\â -DDEF_QUEUE_DIR=\â/var/spool/postfix1\ââ
works finefor me
make give following errors
mail_conf.c: In function âmail_conf_checkdirâ:
mail_conf.c:119: error: stray â\342â in program
mail_conf.c:119: error: stray â\200â in program
mail_conf.c:119: error: stray â\235â in program
mail_conf.c:119: error: expected expression before â/â token
mail_conf.c:119: error: stray â\342â in program
mail_conf.c:119: error: stray â\200â in program
mail_conf.c:119: error: stray â\235â in program
mail_conf.c: In function âmail_conf_suckâ:
mail_conf.c:170: error: stray â\342â in program
mail_conf.c:170: error: stray â\200â in program
mail_conf.c:170: error: stray â\235â in program
mail_conf.c:170: error: expected expression before â/â token
mail_conf.c:170: error: stray â\342â in program
mail_conf.c:170: error: stray â\200â in program
mail_conf.c:170: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
mail_conf.c:178: error: expected expression before â/â token
mail_conf.c:178: error: stray â\342â in program
mail_conf.c:178: error: stray â\200â in program
mail_conf.c:178: error: stray â\235â in program
make: *** [mail_conf.o] Error 1
make: *** [update] Error 1
Awesome âto the point. Enjoyed reading it. Thanks!
Please can you explain how to link a phplist instance with multiple postfix instances(5 postfix instances for ex)?
Thanks a lot
Thanks for the article. But why not use postmulti?
Any reason why you didnât use the postfix package provided by your Linux Distribution?
PS: @Ellio, yeah, postmulti is the way to go.