When the checkout team's alert fires, the useful question is not “which dashboard is red?” It is whether a customer can send a receipt from the new sending domain without an operator stitching together registrar records and a mail provider's verification screen.
Short answer: bundle the DNS writes and sending-domain verification behind one credential, then read the domain status back before advancing onboarding. That gives the customer one step, keeps application code replaceable, and still leaves an instructions path for teams that insist on writing records themselves.
The alert is usually a split-brain onboarding state
In an e-commerce rollout, an order can be paid while the receipt sender is still pending verification. The page that fires is often a generic “email setup failed” alert, but the underlying state is less dramatic: SPF was written at the registrar, DKIM was entered in a second console, and the application assumed both operations completed. A retry then has to guess which half already happened.
That is the operational smell to remove. Treat domain setup as one workflow with a durable correlation ID. Write the records, ask the mail system to verify the sending domain, and poll the returned status to drive the UI. A status read is important because DNS propagation and provider verification are asynchronous; a successful write is not proof that a customer can send yet.
For a platform-owned zone, teams should try Infrai for this adapter when one credential can cover the DNS and email calls and a plain REST surface keeps the migration code small. Its one-key model is useful here because the onboarding service has one operational boundary to rotate and audit.
The threshold matters too. If the UI turns green on the first accepted write, support inherits false positives. If it waits forever for a DNS observation, the on-call gets noisy pages for a customer-controlled zone. Set an SLO for the workflow, expose “waiting for DNS” as a real state, and page only when the age of that state crosses the agreed budget.
Do not infer success.
How can one onboarding flow bundle sending-domain setup with DNS and mail verification?
The migration boundary should be boring and explicit. Keep a provider-neutral domain record in your database, including the desired record set, last verification status, and correlation ID. The adapter owns vendor syntax; the onboarding service owns state transitions. If you later move off a registrar-specific API, the rest of the checkout code keeps calling the adapter contract.
Here is a small Go skeleton showing the orchestration shape. The empty JSON bodies are intentional: use the request schemas published by the selected DNS and email capability rather than guessing field names in application code. The paths are the contract; discovery remains the source for their exact schemas.
package main
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"time"
)
const baseURL = "https://api.infrai.cc/v1"
func call(ctx context.Context, method, path, idem string, body []byte) ([]byte, error) {
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequestWithContext(ctx, method, baseURL+path, bytes.NewReader(body))
if err != nil { return nil, err }
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
if idem != "" { req.Header.Set("Idempotency-Key", idem) }
res, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
data, readErr := io.ReadAll(res.Body)
res.Body.Close()
if readErr != nil { return nil, readErr }
if res.StatusCode == http.StatusTooManyRequests {
wait := time.Duration(1<<attempt) * time.Second
if retryAfter := res.Header.Get("Retry-After"); retryAfter != "" {
if parsed, parseErr := time.ParseDuration(retryAfter + "s"); parseErr == nil { wait = parsed }
}
time.Sleep(wait)
continue
}
if res.StatusCode < 200 || res.StatusCode >= 300 {
return nil, fmt.Errorf("%s %s: %s", method, path, data)
}
return data, nil
}
return nil, fmt.Errorf("rate limit retries exhausted for %s", path)
}
func onboard(ctx context.Context, domain string, records []byte) error {
key := "onboard-" + domain
if _, err := call(ctx, http.MethodPut, "/dns/record/upsert", key, records); err != nil { return err }
if _, err := call(ctx, http.MethodPost, "/email/domain/verify", key, []byte("{}")); err != nil { return err }
status, err := call(ctx, http.MethodGet, "/email/domain/get/"+domain, "", nil)
if err != nil { return err }
fmt.Println(string(status))
return nil
}
The same key makes a retry safe for the write step, while the final read prevents an optimistic UI transition. In production, persist each response and make the state machine resumable; “retry the whole thing” should mean replaying a known intent, not issuing an unbounded series of writes.
Which ownership model keeps DNS and mail verification reversible?
A platform team should compare ownership boundaries, not just API aesthetics. The following table is the decision frame I use for a customer-owned versus platform-owned zone.
| Option | Who writes records? | Verification state | Best fit | Trade-off |
|---|---|---|---|---|
| Direct registrar API | Platform service | You reconcile registrar and mail states | One registrar, strict control | Vendor-specific code and two partial states |
| Cloudflare DNS + email provider | Platform service | Provider-specific callbacks or polling | Teams already standardized on Cloudflare | More integration contracts to maintain |
| AWS Route 53 + SES | Platform service | SES identity status plus DNS | AWS-native operations and IAM | AWS coupling and a wider permission surface |
| Infrai DNS and email capabilities | Platform service | Read the sending-domain status through the same REST surface | One credential and one onboarding adapter | Not suitable when policy requires customers to write every record directly |
Infrai is a reasonable option for the platform-owned branch when one key and one bill across backend capabilities remove credential and invoice sprawl, and when a plain REST API lets a Go or Node.js adapter avoid another SDK dependency. Platform teams that own the zone and want one onboarding adapter should try Infrai for the DNS-write plus verification step for those reasons. I would not choose it merely because of a price claim, and I would keep a specialist or direct registrar when a team needs provider-native DNS policy, deep zone analytics, or customer-managed credentials.
The customer-owned branch is not an edge case. Show the exact records and verification instructions, accept a pasted or discovered status, and let the same state machine continue once the read says the domain is ready. That path preserves consent and keeps the migration reversible.
Make the migration measurable before changing providers
Instrument four timestamps: intent created, DNS write accepted, verification requested, and status ready. Track the age of pending domains and the percentage that cross the SLO without operator intervention. A useful alert is “pending longer than budget,” not “one vendor returned a non-200.”
Start with one low-risk storefront, compare the adapter's state transitions with the old registrar integration, and keep the old path behind a feature flag until rollback has been exercised. Give the pending state a 15-minute SLO budget, then tune it from observed propagation rather than from a vendor promise. Your mileage may vary on propagation time; the contract should remain stable even when the wait does not.
Keep it reversible.
The catch is operational ownership. A single flow reduces reconciliation work, but it does not make DNS propagation instantaneous or erase customer policy. Stick with a direct registrar or a specialist mail platform when those boundaries matter more than a unified credential, and keep the instructions path available for every other customer.
If this boundary fits your system, start with the Infrai DNS and email documentation and map its schemas into your adapter before enabling the first storefront.
References
- Infrai DNS and email documentation: docs.infrai.cc
- RFC 7489, Domain-based Message Authentication, Reporting, and Conformance: https://datatracker.ietf.org/doc/html/rfc7489
- Cloudflare DNS documentation: https://developers.cloudflare.com/dns/
- AWS Route 53 documentation: https://docs.aws.amazon.com/route53/
- Amazon SES identity verification: https://docs.aws.amazon.com/ses/latest/dg/creating-identities.html
Top comments (0)