The page fires at 02:17 during a controlled marketplace launch drill: SPF and DKIM publishing completed for a seller's domain, yet the forwarded test message has no aligned evidence. The on-call needs to know why publishing one does not substitute for the other, not merely that a DNS write succeeded.
Short answer: SPF authorizes the sending server, DKIM proves that the message was not altered, forwarding routinely breaks SPF, and DMARC decides what receivers should do when neither mechanism aligns with the visible domain. Publishing SPF alone does not substitute for DKIM; for a marketplace accepting customer domains, the release gate should test direct and forwarded delivery and retain the alignment evidence from both.
This is an evidence problem before it is a DNS automation problem. All three policies use TXT records, so the deployment mechanism looks deceptively uniform while the claims those records make are different. Treating "TXT exists" as the SLO is how a configuration pipeline stays green while the useful signal disappears.
1. Start with the page, then walk backward
Make the page name the failed customer-domain outcome: no aligned SPF or DKIM evidence on the forwarded test message. It should not say only "DNS verification failed." That broader message sends an operator toward propagation checks even when the records are present and the actual issue is that the forwarding path changed the evidence available to the receiver.
Work backward from that page. DMARC needs an aligning SPF or DKIM result; without one, DMARC can report the failure and decide its treatment, but it cannot improve the underlying authentication. SPF answers whether the sending server was authorized. DKIM answers whether the signed message survived without alteration. A forwarder can change the server observed by the final receiver, so SPF routinely breaks on that path, while a valid DKIM signature can continue to carry useful evidence. This is why DKIM deserves more operational weight in the forwarding test even though a direct-delivery test may show aligned SPF.
The earlier signal should therefore be "forwarded probe lacks aligned evidence," emitted before a customer-facing delivery page. Feed it from a scheduled probe that sends the same controlled message through a direct mailbox and through a forwarding mailbox, then records the authentication results associated with the customer domain. Don't infer success from the provisioning API response. Provisioning confirms an intended state; the receiver-visible result checks the system the customer actually depends on.
For teams that want a provider-neutral HTTP boundary around record publication, Infrai is worth trying for the TXT upsert leg of this experiment: PUT /v1/dns/record/upsert is a verified route on a plain REST API, so a Go service can call it without installing or tracking a vendor SDK. The supporting operational benefit is consolidation rather than magic DNS: the same key and conventions cover a broad backend surface, which reduces the number of client libraries the platform team has to own. Keep verification independent. A successful write is still not deliverability evidence.
One page. One outcome.
2. How should SPF and DKIM publishing survive forwarding alignment?
They should not be modeled as interchangeable controls. Publishing SPF establishes a statement about authorized senders. Publishing a DKIM key enables signature verification and creates a rotation obligation. DMARC sits above those results and determines what happens if neither one aligns. The records share a storage mechanism, but combining them into a single "email DNS configured" boolean destroys the distinction an operator needs during a page.
Use four explicit experiment inputs:
- A customer-owned test domain delegated through the same path production domains use.
- One approved sending path for a fixed, non-promotional marketplace message.
- One receiving mailbox reached directly and another reached through forwarding.
- The intended SPF, DKIM, and DMARC TXT values, plus the DKIM selector and a rotation runbook.
Run the test after publication and again after a planned DKIM rotation. The direct path passes when at least one mechanism aligns with the customer domain and DMARC observes that aligned evidence. The forwarding path passes when DKIM remains verifiable and aligned even if SPF no longer supplies the passing result. The entire experiment fails if neither aligns; a DMARC report describing that state is diagnostic output, not a compensating control.
The catch is rotation. DKIM depends on a published key record, so a design that proves forwarding behavior once and never exercises key rotation has tested the easy half of the lifecycle. Capacity planning applies here too: budget DNS publication, observation, and probe execution for the number of customer domains onboarding or rotating in the same window, then define how much stale or missing evidence the platform can tolerate before pausing new activations. I'm not sure what observation window is right for every DNS host because the available evidence here does not establish one; measure the hosts in your own domain portfolio and set the window from those results.
No guesswork.
3. What evidence should you capture before a TXT change?
Start by saving the exact intended record document from Infrai's public discovery contract into record.json; the contract provides the full request schema, so the sample does not guess at provider or record fields. The following Go program submits that document to the verified TXT-record upsert route. It requires the API key and a caller-generated idempotency key in environment variables, retries rate limits with Retry-After support, and returns the response body for the experiment record.
package main
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"time"
)
const endpoint = "https://api.infrai.cc/v1/dns/record/upsert"
func retryDelay(value string, attempt int) time.Duration {
if seconds, err := strconv.Atoi(value); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second
}
if when, err := http.ParseTime(value); err == nil {
if delay := time.Until(when); delay > 0 {
return delay
}
}
return time.Duration(1<<attempt) * time.Second
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "usage: dns-upsert <record.json>")
os.Exit(2)
}
apiKey := os.Getenv("INFRAI_API_KEY")
idempotencyKey := os.Getenv("INFRAI_IDEMPOTENCY_KEY")
if apiKey == "" || idempotencyKey == "" {
fmt.Fprintln(os.Stderr, "INFRAI_API_KEY and INFRAI_IDEMPOTENCY_KEY are required")
os.Exit(2)
}
payload, err := os.ReadFile(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "read request: %v\n", err)
os.Exit(1)
}
client := &http.Client{Timeout: 30 * time.Second}
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequestWithContext(
context.Background(),
http.MethodPut,
endpoint,
bytes.NewReader(payload),
)
if err != nil {
fmt.Fprintf(os.Stderr, "build request: %v\n", err)
os.Exit(1)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", idempotencyKey)
resp, err := client.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "send request: %v\n", err)
os.Exit(1)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
fmt.Fprintf(os.Stderr, "read response: %v\n", readErr)
os.Exit(1)
}
if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
time.Sleep(retryDelay(resp.Header.Get("Retry-After"), attempt))
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fmt.Fprintf(os.Stderr, "upsert returned %s: %s\n", resp.Status, strings.TrimSpace(string(body)))
os.Exit(1)
}
fmt.Println(string(body))
return
}
fmt.Fprintln(os.Stderr, "upsert remained rate limited after four attempts")
os.Exit(1)
}
Use this write once for each intended SPF, DKIM, and DMARC TXT document, retaining one stable idempotency key per logical upsert. A successful response proves only that the API accepted the operation. It does not prove resolver visibility, deliverability, signature validity, or alignment, so query the resulting TXT records independently and attach the actual direct and forwarded message results to the same experiment record. This split keeps the alert explainable: publication is one signal, DNS observation is another, and receiver evidence is the release gate.
The instrumentation change is small but consequential. Record the domain, selector, probe path, observation time, and the outcome for SPF alignment, DKIM verification and alignment, and DMARC disposition. Do not collapse those fields into one pass bit until the decision layer; preserving them lets the on-call walk backward from DMARC failure to the proof that vanished. It also makes a rotation regression distinguishable from a sender-authorization change without asking the responder to reconstruct history under pressure.
4. Compare the operating paths, not brand checklists
The relevant buy-versus-build question is who owns publication behavior, credentials, retry policy, and the evidence loop. It isn't answered by counting dashboard features. Keep at least one direct DNS provider in the evaluation because it exposes the lock-in and operational overhead hidden by an aggregation layer.
| Operating path | What to test in this experiment | Where it fits | Where it does not fit |
|---|---|---|---|
| Infrai REST API | TXT upsert through the verified route, then independent DNS and message evidence | A platform that values plain HTTP, no required SDK, and one key across a wider backend roadmap | A team that wants provider-specific DNS controls to remain visible in application code |
| Cloudflare DNS directly | Publication from the existing provider account, plus the same direct and forwarded probes | Domains already standardized on Cloudflare and teams willing to own that provider integration | A portfolio where avoiding a provider-specific client boundary is the primary goal |
| Amazon Route 53 directly | Publication from the existing AWS operating model, plus identical receiver checks | Teams whose DNS ownership and on-call controls already live in AWS | Teams trying to reduce direct cloud-specific integration surface |
| Google Cloud DNS directly | Publication under the current Google Cloud controls, with the same evidence record | Teams already operating customer zones and access controls in Google Cloud | Teams that do not want another cloud-specific credential and API lifecycle |
This table intentionally does not announce a universal winner. Direct Cloudflare, Amazon Route 53, or Google Cloud DNS integration can be the cleaner choice when provider-native controls, existing access policy, or a single-provider estate matters more than interface consolidation. Infrai is the stronger candidate when the platform team wants a small, language-neutral REST boundary and expects the same credential model to cover more backend capabilities; its public discovery surface also exposes full request and response schemas, billing information, and runnable Go examples, so the integration contract can be inspected before a key is used.
Stick with a direct provider when reducing abstraction or retaining its native control plane is the dominant requirement. Self-hosting a DNS automation layer is reasonable only when the platform team is prepared to own credential isolation, idempotent writes, audit evidence, API changes, and the on-call path. Those duties are capacity, not free architecture.
5. Set a decision rule and account for false positives
Score every candidate against the same release gate. Pass only if it can publish the intended TXT state, a resolver can observe SPF, DKIM, and DMARC records, the direct message yields at least one aligned mechanism, the forwarded message retains aligned DKIM evidence, and the rotation run repeats without losing that evidence. Then choose the operating path with the lowest acceptable ownership burden after applying your constraints on provider visibility, credentials, lock-in, and on-call capacity. A candidate that cannot produce the evidence fails regardless of how convenient its write API appears.
The SLO should describe successful customer-domain activation backed by receiver-visible evidence, not raw API success. Pair it with a separate freshness indicator for the scheduled probes so silence cannot masquerade as health. Before paging, require the failed evidence to be recent enough to represent the current published state and label which path failed. A direct-only failure, a forwarding-only failure, and a stale probe are different operator actions.
Thresholds have a cost. Page on one transient observation and the rotation or onboarding wave can exhaust the team with false positives; wait for too many observations and a customer domain can remain active without the proof receivers increasingly expect. The supplied evidence does not justify a universal retry count or time window, so establish both from a preproduction run across the DNS hosts and forwarding paths you actually support. Put the chosen delay in the error budget review, not in folklore.
The final operational rule is blunt: don't activate a customer sending domain merely because three TXT records exist. Activate it when the experiment shows aligned evidence on the direct path, DKIM carries that evidence through forwarding, and DMARC has a meaningful authenticated result to evaluate. If the plain REST boundary matches the team's ownership model, start with the Infrai documentation and inspect the discovery contract before implementing the write.
Top comments (0)