• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion

Input Solution for adding DKIM cname records in DNS

mr-wolf

Silver Pleskian
Plesk Guru
To let a third-party mail using your own domain as sender and having properly implemented DKIM yourself you may come to realize that Plesk isn't helping you.

Some third-party mailers tell you to add a TXT-record containing their public key in your DNS.
This is not really the way to do it.

This way they will not be able to rekey their selector.
On top of never re-keying their selector these third-party mailers often have a 1024-bits key as they fit nicer into DNS. It becomes even more ugly than that. These mass-mailers will often also use that 1 key with its infinite lifetime to secure all their clients....

All these combinations suddenly doesn't make it that far fetched that some spammer or spearfisher takes the time to use bruteforce to find out that mass-mailer's key.

Luckily these mass-mailers are upping their game and they now are starting to use CNAMEs to distribute their public key. That's not enough as most do not have different cnames for each client. They are also, most probably, never changing their key either as this would need 2 selectors instead of one.

Microsoft is doing all this properly with their Office365. Check that out!!

All I've written thus far is just an introduction to make clear for which problem I have a solution.

When trying to implement, for instance, the CNAME that mass mailer Mailchimp is using you will notice that it's impossible to add that to your DNS.
upload_2017-9-7_11-25-33.png

That's because the Plesk webdeveloper decided to forbid the underscore character in the target.
The underscore character is already some time a valid one to use in domain names.
It was at the time when he needed to correct his other mistake when he added the _TCP / _UDP restriction to SRV-records.
Luckily this restriction is only made by Plesk's web developer and the CLI is working fine.

Somehow it takes them several years to correct their mistake. He added a restriction no-one asked for and somehow it isn't given any priority to take that out. I can't wait for that.

Although Microsoft is using an underscore in the CNAMEs they provide, they don't have to. I noticed that mailchimp isn't using it. Anyhow, I wanted to create a script that would not let me have to use the flexible CLI DNS tool and make those changes for me.

The result is this script.
The script takes a domain name as a parameter on the CLI.
The 2nd parameter is provided by the symbolic link.

The script's name is add_dkimspf
If you want to add the DKIM-record and SPF for mailchimp you need to create a symbolic link called "mailchimp" and point that to add_dkimspf
Code:
ls -altr /usr/local/sbin/mailchimp
lrwxrwxrwx 1 root root 27 Jul 26 12:40 /usr/local/sbin/mailchimp -> /usr/local/sbin/add_dkimspf

Then create a file called /usr/local/sbin/mailchimp.records and add the DKIM-record and selector.

ln -s add_dkimspf /usr/local/sbin/mailchimp
cat /usr/local/sbin/mailchimp.records

Code:
SELECTOR1=k1
DKIM1=dkim.mcsv.net
INCLUDE=servers.mcsv.net

Adding the Mailchimp's DKIM-record and SPF-record to the domain yourclient.com becomes as easy as:
Code:
mailchimp yourclient.com

Adding another service is as easy now as creating the *.records file with that service's records and a symbolic link to /usr/local/sbin/add_dkimspf

An example for another service:

ln -s add_dkimspf /usr/local/sbin/efactuur
cat /usr/local/sbin/efactuur.records

Code:
SELECTOR1=efactuur
DKIM1=dkim.efactuurdirect.nl
INCLUDE=_spf.efactuurdirect.nl

Note that the script can also take DKIM2 and SELECTOR2 in the file.

Ironically this script does not work for Microsoft's DKIM as they have a different DKIM-key for each client. I have created a separate script for that.

The record for Mailchimp does not contain underscores and would therefore not be a problem. Other services may be tempted to use an underscore in their records. I have no other examples than Microsoft.

The script is much easier than firing up the Plesk interface anyhow and also prevents you from making a mistake.

Do take care that your SPF-record doesn't need more than 10 resolves to decypher. If it does, it may get discarded by the recipient.

[EDIT]
Noticed that script contained remnants of another script that I took as a template for this one.
Deleted those... (they weren't doing anything)

cat /usr/local/sbin/add_dkimspf
Code:
#!/bin/bash

HEADLESS=
tty >/dev/null || HEADLESS=true

THISSCRIPT="`readlink -f $0`"
SCRIPTNAME=${THISSCRIPT##*/}
BASE=${THISSCRIPT##*/}
[ -z "${BASE}" ] && BASE=${0##*/}

RECORDS=${0}.records
LOG=/var/log/${SCRIPTNAME}.log

SELECTOR1=
SELECTOR2=
DKIM1=
DKIM2=
INCLUDE=
DOMAIN="`echo $1 | egrep '^[a-z0-9-]+\.[a-z0-9-]+$'`"

if [ -z "${DOMAIN}" ] ; then
  echo "I need a valid domain" >&2
  exit 1
fi

if ! grep -q "^DKIM1=" ${RECORDS} 2>/dev/null ; then
  echo "There's no file called ${RECORDS} containing SELECTOR1=, DKIM1= and INCLUDE=" >&2
  exit 1
fi

. ${RECORDS}

if [ -z "${DKIM1}" ] || [ -z "${SELECTOR1}" ] || [ -z "${INCLUDE}" ] ; then
  echo "One of the parameters (DKIM1, SELECTOR1, or INCLUDE) is empty"
  exit 1
fi

# Clean up some parameters
echo "${DKIM1}"    | grep -q "\.$" || DKIM1="${DKIM1}."                  # Add a dot to the domain
echo "${INCLUDE}" | grep -q "^include:" || INCLUDE="include:${INCLUDE}"  # Precede include: if it's not there

TMPDIR=`mktemp -t -d ${0//*\/}.XXXXXXXXXX`
TMPLOG=${TMPDIR}/log
date >${TMPLOG}

# Collect all the Plesk domains
mysql --skip-column-names -uadmin -p`cat /etc/psa/.psa.shadow` psa -e "SELECT domains.name FROM domains ORDER BY domains.name ASC; " 2>/dev/null | egrep -v '\..+\.' | tr 'A-Z' 'a-z' | sort -uo ${TMPDIR}/plesk_domains

if ! grep -q "^${DOMAIN}$" ${TMPDIR}/plesk_domains ; then
  echo "The domain ${DOMAIN} does not exist on this server" >&2
  echo "These exist:"
  grep "^`echo ${DOMAIN} | cut -b1`" ${TMPDIR}/plesk_domains | sed 's/.*/\t&/g'
else
  SPF_FOUND="`host -t txt ${DOMAIN} localhost 2>/dev/null | grep -o "v=spf1.*all"`"
  DKIM1_FOUND="`host ${SELECTOR1}._domainkey.${DOMAIN} localhost 2>/dev/null | grep -o "is an alias for .*"`"

  if [ -z "${DKIM1_FOUND}" ] ; then
    echo "Add DKIM ${SELECTOR1}._domainkey.${DOMAIN} to ${DKIM1}" | tee -a ${TMPLOG}
    /usr/local/psa/bin/dns --add ${DOMAIN} -cname ${SELECTOR1}._domainkey -canonical ${DKIM1} | tee -a ${TMPLOG}
  else
    DKIM1_TARGET="`echo ${DKIM1_FOUND} | awk '{print $5}'`"
    if [ "${DKIM1_TARGET}" == "${DKIM1}" ] ; then
      echo "DKIM ${SELECTOR1}._domainkey.${DOMAIN} pointing to ${DKIM1} is already added"
    else
      echo "error!! DKIM ${SELECTOR1}._domainkey.${DOMAIN} points to ${DKIM1_TARGET} not ${DKIM1}"
    fi
  fi

  # If the 3rd party mailer is using 2 keys
  # They should really, this is an indication that their keys are never rotated
  if [ -n "${DKIM2}" ] && [ -n "${SELECTOR2}" ] ; then
    echo "${DKIM2}" | grep -q "\.$" || DKIM2="${DKIM2}."    # Add a dot to the domain

    DKIM2_FOUND="`host ${SELECTOR2}._domainkey.${DOMAIN} localhost 2>/dev/null | grep -o "is an alias for .*"`"
    if [ -z "${DKIM2_FOUND}" ] ; then
      echo "Add DKIM ${SELECTOR2}._domainkey.${DOMAIN} to ${DKIM2}" | tee -a ${TMPLOG}
      /usr/local/psa/bin/dns --add ${DOMAIN} -cname ${SELECTOR2}._domainkey -canonical ${DKIM2} | tee -a ${TMPLOG}
    else
      DKIM1_TARGET="`echo ${DKIM2_FOUND} | awk '{print $5}'`"
      if [ "${DKIM2_TARGET}" == "${DKIM2}" ] ; then
        echo "DKIM ${SELECTOR2}._domainkey.${DOMAIN} pointing to ${DKIM2} is already added"
      else
        echo "error!! DKIM ${SELECTOR2}._domainkey.${DOMAIN} points to ${DKIM2_TARGET} not ${DKIM2}"
      fi
    fi
  fi

  if [ -z "${SPF_FOUND}" ] ; then
    echo "Totally no SPF for ${DOMAIN} is found, I will not make one then"
  else
    if echo "${SPF_FOUND}" | grep -q " ${INCLUDE} " ; then
      echo "The SPF-record already contains ${INCLUDE} (${SPF_FOUND})"
    else
      NEW_SPF="`echo "${SPF_FOUND}" | sed "s/ .all$/ ${INCLUDE}&/g"`"
      echo "Remove SPF for ${DOMAIN} containing \"${SPF_FOUND}\"" | tee -a ${TMPLOG}
      /usr/local/psa/bin/dns --del ${DOMAIN} -domain "" -txt "${SPF_FOUND}" | tee -a ${TMPLOG}
      echo "Add SPF for ${DOMAIN} containing \"${NEW_SPF}\"" | tee -a ${TMPLOG}
      /usr/local/psa/bin/dns --add ${DOMAIN} -domain "" -txt "${NEW_SPF}" | tee -a ${TMPLOG}
    fi
  fi

  cat ${TMPLOG} >>${LOG}
fi

rm -r ${TMPDIR}
 
Last edited:
Hi @IgorG
Can you give me some time to sort that out?
I also do hope you (or your colleagues) don't mind some frustration venting in my post.
I do hope they read it, though.
 
Back
Top