In the first part The first part of this article dealt with the requirements and the potential problems associated with them. The second part now deals with the management of SPF entries. In a relatively small and static environment, you will have very few points of contact with the Sender Policy Framework. As a rule, there are only 2 to 3 entries in the SPF DNS record in small environments, and these usually do not change. However, if, as described in the first article, there are many entries and flattened / smoothed SPF entries are also used, you need to think about how to organize them.
Sender Policy Framework (SPF) as a managed service
Probably the easiest way to keep your SPF entries up to date and manage them according to your requirements is to buy SPF as a managed service. I'll just name three providers at random that I have found:
I haven't tested any of them yet. The providers all work quite similarly: The domain is authorized in a portal and the DNS entries for Sender Policy Framework are then managed by the provider. The providers usually support several services such as DMARC, MTA-STS and SPF.
Script for creating the SPF entries
Another way to create and manage your SPF records at a glance is to use a script. Some providers allow DNS records to be created or updated via API. Here you could use a small script that updates the DNS records when required. Here is an example of what this could look like in PowerShell:
# Define SPF entries
$SPFPrefix = "_spf"
$Domain = "frankysweb.de"
$SPFEntries = @(
"ip4:185.3.235.230",
"include:secure-mailgate.com",
"include:spf.protection.outlook.com"
)
$Policy = "~all"
# Function for resolving SPF entries
function Resolve-SPF {
param (
[string[]]$SPFRecords
)
$resolvedIPs = @()
foreach ($entry in $SPFRecords) {
if ($entry -like "ip4:*") {
# Direct IP addresses
$ip = $entry -replace "ip4:", ""
$resolvedIPs += $ip
} elseif ($entry -like "include:*") {
# Resolve DNS SPF include records
$domain = $entry -replace "include:", ""
$spfTxtRecords = (Resolve-DnsName -Type TXT -Name $domain).Strings -match "v=spf1"
foreach ($record in $spfTxtRecords) {
$tokens = $record -split "\s+"
foreach ($token in $tokens) {
if ($token -like "ip4:*") {
$ip = $token -replace "ip4:", ""
$resolvedIPs += $ip
}
}
}
}
}
return $resolvedIPs
}
# Function for splitting SPF entries into 255 character long parts
function Split-SPF {
param (
[string]$SPFString,
[string]$Policy,
[int]$MaxLength = 255
)
$spfParts = @()
$currentPart = ""
$tokens = $SPFString -split "\s+"
foreach ($token in $tokens) {
# Check whether adding the token and the policy exceeds the length
if (($currentPart.Length + $token.Length + $Policy.Length + 1) -le $MaxLength) {
$currentPart += $token + " "
} else {
# If the length is exceeded, save the current part and start a new one
$spfParts += ($currentPart.TrimEnd() + " " + $Policy)
$currentPart = $token + " "
}
}
# Add the last part
if ($currentPart.TrimEnd().Length -gt 0) {
$spfParts += ($currentPart.TrimEnd() + " " + $Policy)
}
return $spfParts
}
# Function to create the flat SPF entries and split them
function Create-SPF {
param (
[string[]]$ResolvedIPs,
[string]$Policy
)
# Creation of the complete SPF entry
$FlatSPF = ""
foreach ($IP in $ResolvedIPs) {
$entry = "ip4:" + $IP + " "
$FlatSPF = $FlatSPF + $entry
}
# Split the SPF entry if it is too long
return Split-SPF -SPFString $FlatSPF -Policy $Policy
}
# Example of use
$resolvedIPs = Resolve-SPF -SPFRecords $SPFEntries
$SPFEntries = Create-SPF -ResolvedIPs $resolvedIPs -Policy $Policy
# Create main SPF for the domain
$Counter = 1
$MainDNS = "IN TXT `"v=spf1 "
$SubDNS = @()
foreach ($SPFEntry in $SPFEntries) {
# Create the main SPF entry with includes for sub-SPF entries
$MainDNS = $MainDNS + "include:" + "$SPFPrefix" + $Counter + "." + $Domain + " "
# Add sub-SPF entries without 'v=spf1', as it is already in the main SPF
$SubDNS += "$SPFPrefix" + $Counter + "." + $Domain + " IN TXT " + '"' + "v=spf1 " + $SPFEntry + '"'
$Counter++
}
$MainDNS = $MainDNS + $Policy + '"'
# Output of the main SPF entry
write-host "Main SPF Entry for Domain $Domain`:" -foregroundcolor green
write-host "$MainDNS"
# Output of the sub SPF entries
foreach ($entry in $SubDNS) {
write-host "Sub SPF Entry:" -foregroundcolor green
write-host $entry
}
The normal readable SPF entries are specified in the first lines of the script. Flattened SPFs are then generated and displayed from this information. The part with updating the DNS records is of course missing here, as the APIs of the providers are different, so you still have to do this yourself if necessary.

However, it is probably easier to use a managed service, as you usually also get additional features such as DMARC reporting, hosted MTA-STS etc. there.