Appendix C. Generating exim configuration files

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;