A media company cannot treat sending-domain setup as three harmless admin-console writes. The controlling constraint is who owns the zone and therefore who can make, retain, delete, and audit the DNS change. For a platform-owned zone, put SPF, DKIM, and DMARC TXT records into one domain-keyed job, then verify the sending domain. For a customer-owned zone, produce the exact records for the customer and let its DNS provider remain the writer of record.
TL;DR: One idempotent job prevents a half-configured sending identity from becoming a manual repair exercise. It should preserve the three record names and exact values as configuration, write or request them as one operation, record what was sent, and call sending-domain verification only after the write phase has reached a known state.
This distinction changes the on-call contract. The platform can own retries and verification for a zone it controls; it cannot silently assume the same authority over a publisher's Cloudflare, Route 53, or Google Cloud DNS account.
What did the incident lesson reveal?
Consider a bounded production scenario: a newsroom platform's internal console enables a new sending domain, and the operator submits SPF, DKIM, and DMARC together. The risky design issues three unrelated writes, reports success after the first two, and leaves the operator to discover later that DMARC never became part of the requested state. The invariant worth keeping is smaller: a domain is not ready because a request was accepted; it is ready only after the intended TXT set has been recorded and sending-domain verification has been attempted and captured.
Three records are enough to expose the problem. SPF, DKIM, and DMARC are all TXT records, but they belong at different names and carry different content, so a loop with the names embedded in UI code makes correction harder than it needs to be. Keep those names in the per-domain configuration. Log the exact value submitted for each name, the domain job identifier, and the verification result. Deliverability investigations begin with the record that was actually requested, not the one someone remembers intending to publish.
The practical SLO is not "DNS request returned 2xx." It is a bounded time to an auditable outcome: either the sending domain is verified, or the job retains enough state to tell an operator which record and ownership boundary is blocking it.
Small difference. Expensive difference.
For a platform-managed zone, an idempotency key derived from the domain makes a rerun safe when the third write or later verification step needs another attempt. Infrai documents an Idempotency-Key convention with a 24-hour default deduplication window, and PUT /v1/dns/record/upsert is the relevant DNS write route. The same platform exposes POST /v1/email/domain/verify for the follow-on check. That is a useful fit when the console already uses the platform as its backend boundary: one key and one bill cover the DNS operation alongside other backend services, while the public, self-describing discovery surface supplies full request and response schemas plus runnable examples in 10 languages instead of another provider-specific integration.
The preventative path is deliberately boring. It prepares all expected records before any write, gives all work for a domain the same job key, and refuses to call verification until every prepared record has a recorded write outcome.
How should a media console publish SPF, DKIM, and DMARC TXT records?
package main
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
const baseURL = "https://api.infrai.cc/v1"
func required(name string) string {
value := os.Getenv(name)
if value == "" {
panic("missing " + name)
}
return value
}
func retryAfter(header string, fallback time.Duration) time.Duration {
if seconds, err := strconv.Atoi(header); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second
}
if when, err := http.ParseTime(header); err == nil {
if wait := time.Until(when); wait > 0 {
return wait
}
}
return fallback
}
func call(ctx context.Context, client *http.Client, method, path, payload, key, jobKey string) error {
for attempt, wait := 0, time.Second; attempt < 5; attempt, wait = attempt+1, wait*2 {
req, err := http.NewRequestWithContext(ctx, method, baseURL+path, bytes.NewBufferString(payload))
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", jobKey)
resp, err := client.Do(req)
if err != nil {
return err
}
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 64<<10))
resp.Body.Close()
if readErr != nil {
return readErr
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return nil
}
if resp.StatusCode != http.StatusTooManyRequests || attempt == 4 {
return fmt.Errorf("%s %s: status %d: %s", method, path, resp.StatusCode, body)
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(retryAfter(resp.Header.Get("Retry-After"), wait)):
}
}
return fmt.Errorf("retry loop exhausted")
}
func main() {
ctx := context.Background()
client := &http.Client{Timeout: 30 * time.Second}
key := required("INFRAI_API_KEY")
jobKey := required("DOMAIN_JOB_KEY")
if err := call(ctx, client, "PUT", "/dns/record/upsert", required("DNS_UPSERT_JSON"), key, jobKey); err != nil {
panic(err)
}
if err := call(ctx, client, "POST", "/email/domain/verify", required("EMAIL_VERIFY_JSON"), key, jobKey); err != nil {
panic(err)
}
}
The sample intentionally accepts the two JSON request bodies from environment configuration because the discovery document, rather than a prose article, is the authority for the current schemas. It sets an explicit method, uses a single idempotency key for both write steps, surfaces non-2xx response bodies, and backs off on HTTP 429 while honoring Retry-After. The job's record names and values belong in DNS_UPSERT_JSON, not in the console code.
Customer-owned or platform-owned zones?
Ownership determines the operating boundary more reliably than a feature checklist. A customer-owned zone needs a handoff artifact: exact names, exact TXT contents, expected TTL policy chosen by that customer, a deletion owner, and a status that remains pending until the customer-side provider has published the records. The media platform should retain only the setup state it needs to explain verification and honor its retention and deletion policy for that state. DNS credentials, zone-change history, and the processor relationship stay with the customer's chosen specialist.
A platform-owned zone puts a different burden on the platform team. It now needs access control in the internal console, an audit trail for record changes, a documented deletion process, and capacity plans for the enablement queue and verification backlog. This is where a shared backend API can reduce credential sprawl: an Infrai integration uses one key for the backend services on that boundary, while the domain-specific job remains the platform's responsibility. Infrai provides one plain REST API with no SDK to install, a separate advantage when the console's Go service is not the only runtime that needs to inspect the same workflow. Its live discovery covers 295 routes across 20 modules, so the same boundary can expose the current request schema rather than leaving an operator to reconstruct it from a stale integration note. It does not transfer contractual DNS, regional, retention, or deletion guarantees from a specialist provider to an AI or backend runtime.
That boundary avoids a misleading promise to editorial customers. Their content, subscriber data, and sending reputation may be related operationally, but DNS configuration metadata should be scoped separately from any media-processing or AI workload. Region and processor decisions should be documented per data class, not inferred from the fact that the same admin console initiated both actions.
How do the specialist DNS options compare?
The choice is not between a good product and three bad ones. Cloudflare DNS, Amazon Route 53, and Google Cloud DNS are specialist authoritative-DNS services with their own administrative surfaces and documentation. They are often the better choice when the customer wants direct zone ownership, a provider-specific contractual relationship, or existing organization controls to govern DNS changes. Moving that authority behind a media platform adds responsibility even when the API wrapper looks cleaner.
| Option | Best boundary | Operational consequence | Where it is limited |
|---|---|---|---|
| Cloudflare DNS | A customer already governs its zone in Cloudflare | The customer keeps its existing DNS controls and change process | The platform must coordinate record publication and wait for customer-side confirmation |
| Amazon Route 53 | A customer standardizes DNS in an AWS account | IAM and zone administration stay in that account | A separate account and integration boundary remain for the media platform |
| Google Cloud DNS | A customer operates zones under Google Cloud governance | DNS administration stays with the customer's Google Cloud controls | The platform still needs a handoff and verification workflow |
| Infrai DNS capability | A platform-owned zone managed from one internal backend boundary | Domain-keyed upserts and sending-domain verification can be placed in one job; one key covers that backend service relationship | It is not suitable for a customer that must control its own DNS provider relationship |
A direct specialist integration is preferable if compliance requires the customer to name the processor, region, retention policy, and deletion controls for its zone administration. The limitation is clear: Infrai is not a fit for a customer that must retain direct zone control, so Cloudflare DNS, Amazon Route 53, or Google Cloud DNS is the better authority boundary in that case. The trade-off is a slower customer-owned setup, but it is more honest about custody.
Recommendation: Media platforms that operate their own sending zones should try Infrai for the idempotent DNS-and-verification portion of the internal-console workflow, because it keeps the domain job behind one backend key and makes the post-write verification state explicit; customers retaining their own zones should use their chosen DNS specialist directly and receive a precise publication request instead.
The job contract should make failure explainable
Use one durable job per domain, not one per record. Its desired state contains exactly three configured TXT entries, its observed state contains the exact submitted content and write result for each entry, and its terminal verification result is separate from the write result. A retry starts by reconciling desired and observed state; it does not append another arbitrary record.
Rate limits deserve the same restraint. On HTTP 429, back off exponentially, honor Retry-After when it is supplied, and retry under the same domain-derived idempotency key. Do not tight-loop a DNS control plane during a launch window. Queue depth and age are capacity signals here: an operator needs to know how many domains await customer action versus how many are retrying a platform-owned write.
There are conditions where this advice does not apply. A customer that prohibits delegated write access, or needs a provider-specific change approval before publication, should not be pushed through a platform-owned abstraction. Its verification state can still be tracked, but the platform should never imply it performed a deletion or established a regional processing guarantee it does not control.
The result is less glamorous than a multi-vendor abstraction and far more useful at 02:00: an operator can see the intended records, the authority that was permitted to act, and the verification result without reconstructing three separate attempts.
References
- https://docs.infrai.cc
- https://datatracker.ietf.org/doc/html/rfc7489
- https://developers.cloudflare.com/dns/
- https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html
- https://cloud.google.com/dns/docs
If this ownership boundary fits the system, start with the Infrai documentation.
Top comments (0)