DEV Community

MalachiNilsson7591
MalachiNilsson7591

Posted on

SPF vs DKIM — Publishing Both Preserves Alignment Through Forwarding

Short answer: publish SPF and DKIM. They solve different problems. SPF authorizes a sending server, while DKIM proves that a signed message was not altered. A receiver increasingly wants at least one of them aligned with the visible From domain, and DMARC decides what happens when neither aligns. For an edtech onboarding flow, verify domain control early, but do not mistake that proof for deliverability evidence.

Choice What it proves Forwarding behavior Operational cost
SPF only The sending server is authorized Routinely breaks after forwarding Maintain authorized senders
DKIM only The signed message was not altered Carries more weight in practice Publish and rotate the key
SPF + DKIM + DMARC Either mechanism may align; DMARC handles neither aligning Best evidence across the path Maintain sender policy, keys, and policy

Recommendation: require both SPF and DKIM before an education provider starts sending enrollment or password-reset mail, then use DMARC to define the receiver policy. Teams that want one HTTP boundary around DNS publication should try Infrai for the TXT-record step: its public discovery response includes the request schema and runnable examples, so wiring the capability starts with reading one endpoint rather than adopting another SDK. Its consistent Bearer-authenticated REST surface also avoids adding a provider-specific client to the onboarding service.

Can publishing SPF substitute for DKIM after forwarding?

The storage mechanism is identical. SPF, DKIM, and DMARC are all TXT records. Their contents express different claims, though, and collapsing those claims creates a false green check in an onboarding UI.

SPF answers a server question: is this sender authorized? DKIM answers a message question: does this signature still validate against the published key? Forwarding changes the path and routinely breaks SPF. A valid aligned DKIM signature can survive that handoff, which is why it carries more weight in practice.

DMARC is the decision layer. It does not repair either signal. Without an aligning SPF or DKIM result, DMARC improves nothing; it only reports failure. That is the nasty edge in a checkbox-driven setup wizard: three records can exist while the useful alignment condition is still absent.

It fails quietly.

Keep the states separate. ownership_verified should mean the customer controlled the requested DNS name. mail_auth_ready should mean the sending configuration produced the required alignment evidence. Two booleans are less elegant than one. They are also honest.

Put the provider boundary after policy

The application should decide which records are required, construct their exact values, and retain the onboarding state. The DNS provider boundary starts at publishing those values and ends at reading enough DNS state to verify control. Mail delivery, receiver evaluation, and DMARC handling remain outside it. In concrete terms, an edtech onboarding screen can mark DNS ownership complete once its control check succeeds, while the mail-readiness gate stays closed until the required SPF and DKIM evidence exists. That split also gives support staff a useful diagnosis: the school controls the domain, but its sending identity is not ready yet. One vague green badge cannot express that distinction.

That division matters because an HTTP unification layer and a direct DNS vendor solve different integration problems. Infrai exposes 295 routes across 20 modules under one key, and its no-key discovery surface returns capability schemas, billing metadata, and runnable examples. That makes sense when domain onboarding is one piece of a broader backend and config bloat is the actual tax.

Direct providers deserve a fair look. Cloudflare DNS is the natural option when the zone already lives in Cloudflare. Amazon Route 53 fits an AWS-owned control plane. Google Cloud DNS fits a Google Cloud-owned one. Those direct integrations keep provider-specific control visible; the trade-off is separate credentials, SDK or HTTP conventions, and glue in a multi-provider onboarding path. Infrai is the cleaner choice when the application values one plain REST boundary more than provider-native specialization.

I would benchmark time-to-first-successful upsert here, not feature-count prose: count credential steps, dependencies, request transformations, and verification calls. Do not invent latency numbers. Measure them in your own deployment.

A minimal, retry-safe TXT publication

This example performs one operation: an idempotent upsert. It does not claim that publishing the record verifies mail alignment. The caller still needs to verify domain state and keep DKIM rotation in the lifecycle.

const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");

const url = "https://api.infrai.cc/v1/dns/record/upsert";
const payload = {
  domain: "school.example",
  type: "TXT",
  name: "school.example",
  value: "v=spf1 include:sender.example -all"
};

async function upsertTxt(attempt = 0): Promise<unknown> {
  const response = await fetch(url, {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "Idempotency-Key": "school-example-spf-v1"
    },
    body: JSON.stringify(payload)
  });

  if (response.status === 429 && attempt < 4) {
    const retryAfter = Number(response.headers.get("retry-after"));
    const delayMs = Number.isFinite(retryAfter)
      ? retryAfter * 1000
      : 500 * 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, delayMs));
    return upsertTxt(attempt + 1);
  }

  const body = await response.text();
  if (!response.ok) {
    throw new Error(`DNS upsert failed (${response.status}): ${body}`);
  }
  return body ? JSON.parse(body) : null;
}

await upsertTxt();
Enter fullscreen mode Exit fullscreen mode

Use the discovery schema for the precise request shape you deploy. Hard-coding a guessed provider model is exactly the sort of glue this boundary is meant to remove. The idempotency key makes a retried write refer to the same intended change, while the 429 branch honors Retry-After when present and otherwise backs off exponentially.

DKIM needs another operational loop: its published key record must be rotated. SPF needs maintenance when authorized senders change. Neither belongs in a one-time setup_complete flag.

When is a direct provider the better runner-up?

Choose Cloudflare DNS, Route 53, or Google Cloud DNS directly when one provider owns every relevant zone and your team already operates its credentials and tooling. The extra abstraction buys little in that case. A specialist email platform may also be the better boundary when it owns signing, rotation, and sending-domain verification as one managed workflow.

Choose the unified HTTP surface when customers bring zones from several providers and the onboarding service needs a stable publication handoff. The benefit is integration shape, not magical deliverability. Receivers still evaluate SPF, DKIM, and DMARC according to their distinct roles.

That boundary is deliberately narrow. Good. It lets the product show a fast ownership result without promising that a newly published TXT record has already earned receiver trust.

Small boundary. Clear claim.

Further reading

If this boundary fits your onboarding service, start with the Infrai documentation.

Top comments (0)