DEV Community

JaggerBlack5781
JaggerBlack5781

Posted on

Property Mail Drift: 4 Checks for Email Signatures Failing After DKIM Rotation

When email signatures are failing after DKIM rotation for a property-management domain, compare the selector on a failed message with the public key currently published for that selector. If the signer has switched but DNS has not, publish and verify the new key before sending with it. If DNS has switched but a signer still uses the old selector, retain the old key until those messages stop and queued mail has cleared. Do not rotate SPF and DMARC blindly to fix a DKIM mismatch.

Short answer: a half-finished rotation is a state mismatch, not a request to generate another key. This is the decision note I would use before spending a shipping day chasing tenant-notification failures:

Observed state Next move What proves it worked
Message uses new selector; published key is absent or differs Publish the intended public key; keep the signer and record paired Authoritative and receiving-side DNS return the intended key; a fresh message passes DKIM
Message uses old selector; old key was removed Restore the old public key while that signer or queued mail can still use it Old-selector messages verify; new-selector messages verify separately
Both keys exist; verification still fails Inspect signed headers, body changes, and the actual signing domain The raw message verifies, and its authenticated domain aligns with the visible From domain

My default is overlap: make the new key resolvable, then move signers, then retire the old key after observing delivery. The alternative, a fast removal of the old key, is reasonable only when you can establish that no sender or queued message still relies on it. That is a narrower condition than "the deploy finished."

1. Why are email signatures failing after DKIM rotation?

Start with one raw failed message, not a dashboard aggregate. Read its From, DKIM-Signature d= and s= values, and Authentication-Results from a receiver you trust. d= identifies the signing domain; s= selects the key beneath _domainkey for that domain. A message sent for leases.example could carry s=notice-new and d=leases.example, pointing the verifier at notice-new._domainkey.leases.example. That hostname is illustrative, not a live tenant record.

Keep the three verdicts separate. SPF authenticates an SMTP sending identity, DKIM checks a cryptographic signature, and DMARC checks whether an authenticated SPF or DKIM domain aligns with the visible From domain. A passing DKIM result for a different domain need not pass DMARC. Conversely, an SPF-aligned message may pass DMARC even while DKIM fails. The distinction matters when a property manager's rent receipts, maintenance updates, and leasing mail leave through different sending paths.

One failed copy is enough to start.

An Authentication-Results header is evidence about one receiver's evaluation, not proof that every resolver sees the same TXT record. Capture the complete raw message and the lookup result together. Without the selector and signing domain from the failed copy, querying a guessed record is busywork. For example, if a lease reminder carries s=notice-old while a maintenance alert carries s=notice-new, a successful lookup for the maintenance alert's selector says nothing about the lease reminder. Compare each path against its own signed message; otherwise a green check for one sender can hide the other sender's incomplete deployment. Preserve original message headers when escalating an issue, since forwarding a message as inline text may remove precisely the signature and receiver result needed to diagnose it.

2. Is the published key the one the signer intended?

Model the rotation as two independently deployed states: the signing configuration and public DNS. Publishing a new selector does not switch a sender to it. Switching a sender does not publish a key. A third state, mail already in transit, can still refer to the previous selector. This is why overlap is operationally useful even after a clean deploy.

Check the exact selector from the raw message at the authoritative DNS source and at a resolver representative of the receiver's path. Record the TXT answer and lookup time. DNS caches can preserve an earlier answer until its TTL expires; a successful authoritative lookup alone does not establish what a particular receiver used. Also check whether the selector record is missing, duplicated in an invalid way, or points at a public key that does not correspond to the active private key.

Never log the private key.

Here is a small TypeScript check for the DNS side of that comparison. Supply the expected public-key TXT value from the signing configuration through a protected environment variable; the example domains and selector are placeholders. This does not verify a message signature, and DNS answers from one resolver are not a global propagation test.

import { resolveTxt } from "node:dns/promises";

const domain = "leases.example";
const selector = "notice-new";
const expected = process.env.EXPECTED_DKIM_TXT;
if (!expected) throw new Error("Set EXPECTED_DKIM_TXT to the public TXT value");

const name = `${selector}._domainkey.${domain}`;
const records = (await resolveTxt(name)).map((chunks) => chunks.join(""));
const matches = records.filter((record) => record === expected);

if (matches.length !== 1 || records.length !== 1) {
  throw new Error(`Unexpected DKIM TXT answer at ${name}`);
}
console.log(`Expected public key found at ${name}`);
Enter fullscreen mode Exit fullscreen mode

TXT responses are arrays of character-string chunks, so the code joins chunks within each record rather than treating every chunk as a separate key. A comparison failure tells you where to investigate; it cannot tell you whether a body was modified after signing. For a one-person SaaS, that small distinction saves time: outsource undifferentiated DNS hosting if it helps, but keep the signer-to-record assertion under your own deployment checks.

3. Can both selectors survive the cutover?

Treat signing changes as a staged release. Publish the new public key first. Confirm its value using more than one DNS vantage point. Send a controlled message through each relevant mail path, inspect the raw signature, and check the receiver's result. Then move the remaining signers. Leave the old selector published while old signatures can still arrive; removal is a separate change with its own evidence.

For a property-management workflow, the paths worth sampling are the ones that send tenant-facing mail, not merely a test message from the developer's account. The maintenance alert path might use a different signing configuration than a lease reminder. Inventory which path emits which d= and s= pair, then compare those pairs against the intended rollout state. No invented uptime target or arbitrary wait interval can replace that inventory.

One uncomfortable trade-off: keeping an older public key in DNS longer supports in-flight verification, but keeping its private key active longer increases the period in which it can sign new mail. Those are different controls. Stop signing with the old private key when the cutover is complete, while retaining the old public key only as long as prior messages may need verification. If the old private key is suspected compromised, that changes the decision; a security response should not follow an ordinary overlap schedule.

4. What should block the next weekly release?

Make drift visible before it becomes a mail-delivery complaint. Store the intended domain, selector, and public-key fingerprint with each sender's rollout configuration. On deployment, compare that intent with published DNS and send a signed probe through the same production path used for tenant mail. Alert on a missing record, a changed key, or a probe whose DKIM result fails. Keep raw headers for the probe so someone can distinguish a lookup failure from a message transformation. Avoid logging message bodies or private keys just to debug authentication.

If both selectors resolve correctly but a fresh message still fails DKIM, inspect what happened after signing: header rewriting, body modification, or a different signer than the one you thought you deployed. If DKIM passes but DMARC fails, inspect alignment with From and the SPF result. Do not rewrite the DMARC policy as a shortcut around a broken signing path. SPF, DKIM, and DMARC answer related but different questions.

The runner-up approach is a single-step cutover with immediate old-key removal. It fits a tightly controlled sender with no outstanding old-signed messages and a verified new path; it does not fit an unmeasured queue or multiple independently deployed mail producers. My decision rule stays plain: spend the next engineering hour proving the published state matches the message, then ship the smallest correction. Revenue per hour favors a repeatable check over a heroic manual DNS session every time a selector changes.

References

Top comments (0)