This is a little script I use to make sure all domains hosted on my email server have DKIM keys, and to output the TXT records for the corresponding keys. Using this I can quickly get an overview of the records I need to add to publish the public DKIM keys.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/usr/bin/env perl

use strict;
use utf8;
use warnings;

use DBI;
use File::Glob qw( bsd_glob )

# make sure the user is root
if ($> != 0) {
    die "You must run this script as root\n";
}

# connect to the database
my $dsn = 'dbi:Pg:dbname=mail;host=127.1;port=5432';
my $dbh = DBI->connect($dsn, 'postgres', 'nope')
    or die 'Could not connect to the database: ' . $DBI::errstr;

# prepare a statement to select all domains
my $select = $dbh->prepare('SELECT name FROM domains;');
$select->execute();

while (my $result = $select->fetchrow_hashref()) {
    my $domain = $result->{name};
    my $dkim_dir = "/srv/dkim/$domain";

    print "$result->{'name'}\n";

    if (! -d $dkim_dir) {
        mkdir($dkim_dir)
            or die "Failed to create output directory at $dkim_dir: $!\n";
    }

    my @keys = bsd_glob($dkim_dir . "/*.private");

    if (@keys) {
        my $date = '20161201';

        # create a new key
        print "  Generating key at $dkim_dir/$date.private\n";

        system (
            'opendkim-genkey',
            -D => $dkim_dir,
            -b => 4096,
            -r,
            -s => $date,
            -d => $domain
        )
            or die "Generating key failed: $!\n";

        # set permissions
        my $gid = getgrnam('mailnull')
            or die "Failed to retrieve the gid of mailnull\n";
        my $uid = getpwnam('mailnull')
            or die "Failed to retrieve the uid of mailnull\n";

        chown($uid, $gid,
            $dkim_dir,
            "$dkim_dir/$date.private",
            "$dkim_dir/$date.txt"
        );
    }

    foreach my $dkim_file (bsd_glob("$dkim_dir/*.txt")) {
        print "  $dkim_file\n";

        open(my $fh, '<', $txt)
            or die "Failed to open $dkim_file for reading: $!\n;

        while (<$fh>) {
            chomp;

            if (/"(.+?)"/) {
                print "$1";
            }
        }

        print "\n";

        close($fh);
    }
}