Postfix how to balance outgoing emails via multiple IP addresses
The solution is depending on postfix`s TCP_TABLES and a perl script. In my example I`m using 7 different IP address to route outgoing mails, make sure you`ve already the IP addresses you are going to use have been configured on your box.First get a recent postfix rpm from here http://ftp.wl0.org/official/2.9/RPMS-rhel5-x86_64/. This one is built for rhel5/centos5 however should be working without much hassle on rhel6/centos5.
Install the package:
# rpm -Uvh postfix-2.9.1-1.rhel5.x86_64.rpm
Make sure its built with tcp tables support:
# postconf -m
btree
cidr
environ
fail
hash
internal
ldap
memcache
nis
proxy
regexp
static
tcp
texthash
unix
Install the perl module List::util::WeightedRoundRobin:
cpan install /List::util::WeightedRoundRobin/
Create the following perl script and make it executable:
vi /etc/postfix/postfix.pl
#!/usr/bin/perl -w
# author: Hari Hendaryanto <hari.h -at- csmcom.com>
use strict;
use warnings;
use Sys::Syslog qw(:DEFAULT setlogsock);
use List::Util::WeightedRoundRobin;
use Storable;
my $hashfile="/tmp/file.hash";
store {}, $hashfile unless -r $hashfile;
#
# our transports lists, we will define this in master.cf as transport services
# Queued using Weighted Round-Robin Scheduling
#
my $list = [
{
name => 'smtp1:',
weight => 1,
},
{
name => 'smtp2:',
weight => 1,
},
{
name => 'smtp3:',
weight => 1,
},
{
name => 'smtp4:',
weight => 1,
},
{
name => 'smtp5:',
weight => 1,
},
{
name => 'smtp6:',
weight => 1,
},
{
name => 'smtp7:',
weight => 1,
},
];
my $WeightedList = List::Util::WeightedRoundRobin->new();
my $weighted_list = $WeightedList->create_weighted_list( $list );
# $maxinqueue max number of queue in smtp list
my $maxinqueue = scalar(@{$weighted_list});
#
# Initalize and open syslog.
#
openlog('postfix/randomizer','pid','mail');
#
# Autoflush standard output.
#
select STDOUT; $|++;
while (<>) {
chomp;
my $count;
my $hash=retrieve($hashfile);
if (!defined $hash->{"index"})
{
$count = 0;
} else {
$count = $hash->{"index"};
}
if ($count >= $maxinqueue)
{
$hash->{"index"} = 0;
$count = 0;
}
$hash->{"index"}++;
store $hash, $hashfile;
my $random_smtp = ${$weighted_list}[$count];
if (/^get\s(.+)$/i) {
print "200 $random_smtp\n";
syslog("info","Using: %s Transport Service", $random_smtp);
next;
}
print "200 smtp:\n";
}
Execute the script to make sure it`s working and no errors are encountered:
/etc/postfix/random.pl
Configure postfix to use the random generated smtp transport.
Edit /etc/postfix/master.cf, by appending following lines:
## Round-robin outgoing smtp
127.0.0.1:23000 inet n n n - 0 spawn
user=nobody argv=/etc/postfix/random.pl
# random smtp
smtp1 unix - - n - - smtp
-o syslog_name=postfix-smtp1
-o smtp_helo_name=FQDN
-o smtp_bind_address=IP
smtp2 unix - - n - - smtp
-o syslog_name=postfix-smtp2
-o smtp_helo_name= FQDN
-o smtp_bind_address=IP
smtp3 unix - - n - - smtp
-o syslog_name=postfix-smtp3
-o smtp_helo_name=FQDN
-o smtp_bind_address=IP
smtp4 unix - - n - - smtp
-o syslog_name=postfix-smtp4
-o smtp_helo_name=FQDN
-o smtp_bind_address=IP
smtp5 unix - - n - - smtp
-o syslog_name=postfix-smtp5
-o smtp_helo_name=FQDN
-o smtp_bind_address=IP
smtp6 unix - - n - - smtp
-o syslog_name=postfix-smtp6
-o smtp_helo_name= FQDN
-o smtp_bind_address=IP
smtp7 unix - - n - - smtp
-o syslog_name=postfix-smtp7
-o smtp_helo_name= FQDN
-o smtp_bind_address=IP
Replace FQDN with desired hostname and IP with the list of the IP addresses you`d like to use.
Append the following lines to your /etc/postfix/main.cf:
transport_maps = tcp:127.0.0.1:23000
127.0.0.1:23000_time_limit = 3600s
Restart/reload postfix and verify everything is working correctly:
# postmap -q "dummy" tcp:127.0.0.1:23000
smtp4:
# postmap -q "dummy" tcp:127.0.0.1:23000
smtp5:
# postmap -q "dummy" tcp:127.0.0.1:23000
smtp6:
In your logs you should see the different smtp transport beeing used when mails are sent.
And also you get an entry when the perl script is used to provide transport.
THanks :)
Comments