As described in delivering non-SPAM email we used a pair of configuration files to instruct exim how to send email to our end users mailserver.
We used the following script to generate /etc/exim4/hubbed_hosts and /etc/exim4/hubbed_ports based upon the contents of /srv every few minutes. In practise the contents didn't change very often, the only exception was when new domains were added to our service.
Example C-1. Generating exim configuration files.
#!/usr/bin/perl
#
# Update /etc/exim4/hubbed_hosts and hubbed_ports if any of our MX
# destinations have changed, or we've had new domains added to our
# system.
#
# Steve
# --
use strict;
use warnings;
use File::Copy;
use File::Temp qw! tempfile !;
use MS::MD5Sum; # local module. obvious contents.
#
# Hash of arrays.
#
my %hosts;
my %ports;
#
# Read the values
#
foreach my $file ( sort( glob( "/srv/*/mx" ) ) )
{
my $domain = $file;
if ( $domain =~ m!^/srv/([^/]+)/mx$! )
{
$domain = $1;
}
open( FILE, "<", $file )
or die "Failed to read $file - $!";
while( my $line = <FILE> )
{
chomp( $line );
my $port = 25;
# strip optional port
if ( $line =~ /(.*):([0-9]+)/ )
{
$line = $1;
$port = $2;
}
#
# Save the recipient away if present.
#
push (@{$hosts{ $domain }}, $line );
push (@{$ports{ $domain }}, $port ) if ( $port != 25 );
}
close( FILE );
}
#
# Get a temporary file for the hosts
#
my ($fh, $filename) = tempfile();
foreach my $domain ( keys %hosts )
{
my @mx = (@{$hosts{$domain}});
print $fh $domain . " : " . join( " : ", @mx ) . "\n";
}
close( $fh );
#
# If the file contents differ from the existing one then replace it.
#
my $new = md5_sum( $filename );
my $cur = md5_sum( "/etc/exim4/hubbed_hosts" );
if ( $cur != $new )
{
File::Copy::move( $filename, "/etc/exim4/hubbed_hosts" );
}
#
# Now write out the ports too
#
my ($fh2, $filename2) = tempfile();
foreach my $domain ( keys %ports )
{
my @ports = (@{$ports{$domain}});
print $fh2 $domain . " : " . join( " : ", @ports ) . "\n";
}
close( $fh2 );
#
# If the file contents differ from the existing one then replace it.
#
my $new2 = md5_sum( $filename2 );
my $cur2 = md5_sum( "/etc/exim4/hubbed_ports" );
if ( $cur2 != $new2 )
{
File::Copy::move( $filename2, "/etc/exim4/hubbed_ports" );
}
#
# All done
#
exit 0;