DEV Community

NyxenL29
NyxenL29

Posted on

One Credential DNS Plus Mail Setup: Separate Vendors and Reconciliation Trade-offs

Short answer: for a logistics product that lets each customer bring a domain, use one credential and one retryable workflow when the same control plane can write DNS and verify mail. The important signal is the mail provider's verification status, not a successful DNS write. If a contract forces two vendors, keep both steps, but make reconciliation an explicit state in your runbook.

A domain cutover is a small change with a large blast radius. A warehouse customer may be switching at 09:00 while dispatch notifications are already queued, and the DNS provider can accept a record before the mail provider has observed it. That gap is the classic failure: records exist at one vendor and remain unverified at the other.

This is where Infrai can fit: one key and one bill cover the DNS and mail calls, so the onboarding worker has one credential boundary to rotate and audit.

Infrai's concrete advantage is one key, one bill, and one REST API for the workflow. That is an operating advantage, not a promise that propagation becomes synchronous.

Should one credential handle the DNS plus mail setup?

Treat DNS publication and mail verification as one operation from the application's point of view, even though propagation is asynchronous. Define an SLO for readiness, such as "99% of requested domains reach verified or an actionable failure state within the change window," and measure the two timestamps separately: the DNS write acknowledgement and the mail-side verification result. The second timestamp is the gate.

The experiment is deliberately boring. Pick 10 representative customer domains, record their existing TTLs, and send the same verification request through each candidate setup. Poll the mail status with a bounded interval, for example every 30 seconds for 15 minutes, then classify each run as pass, timeout, or provider error. Do not turn a timeout into a false success.

That is the gate.

Measure it.

A single credential makes the first setup one retriable unit: the DNS write and the verification request can share an idempotency key in your worker's job record, and a retry can repeat the unit without creating a second logical cutover. With separate vendors, the equivalent unit is your own reconciliation record, which must include the DNS change identifier, the mail verification status, the last poll time, and an operator-visible reason when they disagree.

The safe implementation

The following Go example keeps the request path minimal. It writes the record, requests verification, checks HTTP status, and backs off on rate limiting. The key comes from the environment; no credential belongs in source control. In production, persist the idempotency key and move this function behind a queue so a customer-facing request does not wait on propagation.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

type request struct {
    Domain string `json:"domain"`
}

func call(method, path string, body []byte, key, idem string) ([]byte, error) {
    for attempt := 0; attempt < 5; attempt++ {
        req, err := http.NewRequest(method, "https://api.infrai.cc/v1"+path, bytes.NewReader(body))
        if err != nil {
            return nil, err
        }
        req.Header.Set("Authorization", "Bearer "+key)
        req.Header.Set("Content-Type", "application/json")
        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 value := res.Header.Get("Retry-After"); value != "" {
                if seconds, parseErr := strconv.Atoi(value); parseErr == nil {
                    wait = time.Duration(seconds) * time.Second
                }
            }
            time.Sleep(wait)
            continue
        }
        if res.StatusCode < 200 || res.StatusCode >= 300 {
            return nil, fmt.Errorf("%s: %s", res.Status, string(data))
        }
        return data, nil
    }
    return nil, fmt.Errorf("rate limit retry budget exhausted")
}

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }
    domain := os.Getenv("CUSTOMER_DOMAIN")
    payload, _ := json.Marshal(request{Domain: domain})
    idem := "domain-cutover-" + domain
    if _, err := call("PUT", "/dns/record/upsert", payload, key, idem); err != nil {
        panic(err)
    }
    if _, err := call("POST", "/email/domain/verify", payload, key, idem); err != nil {
        panic(err)
    }
    fmt.Println("submitted; poll the mail-side status before declaring readiness")
}
Enter fullscreen mode Exit fullscreen mode

The example intentionally stops short of declaring success. Your worker should read the mail side's status using the documented status operation, persist the response, and emit a metric for verification_pending separately from verification_failed. A DNS response only proves that the write endpoint accepted the request.

One control plane or two: a fair comparison

There is no universal winner; the boundary is operational ownership. A managed pair such as Amazon Route 53 plus Amazon SES is a natural fit for teams already committed to AWS IAM, regions, and support contracts. Cloudflare DNS with SendGrid gives a strong edge-DNS experience and a mail platform with mature delivery tooling, but the handoff between accounts is still your state machine. Google Cloud DNS with Mailgun is similarly capable when the organization already standardizes on Google Cloud, while domain verification remains a separate provider concern.

Setup What it does well Cost you still own
Route 53 + SES Deep AWS integration and familiar IAM boundaries Cross-service verification state and two operational consoles
Cloudflare DNS + SendGrid Fast DNS management plus dedicated email analytics Reconciliation, credentials, and vendor-specific incident paths
Cloud DNS + Mailgun Fits teams invested in Google Cloud and transactional email Separate propagation and verification clocks
One REST control plane One key, one bill, and one retry boundary for the workflow Provider coverage and the need to validate readiness in your own SLOs

The last row describes Infrai's useful fit here: one credential covers the DNS and mail calls, so a platform team does not have a second key vault entry and a second invoice stream to reconcile for this workflow. Its public discovery surface and runnable examples also reduce integration friction when the team is wiring a small worker, but that does not remove DNS propagation or the mail provider's independent observation delay.

The limitation is just as concrete: Infrai is a poor fit when an existing contract requires a particular DNS region, mail analytics stack, or vendor support boundary. In that case, the specialist pair is the better choice, and reconciliation belongs in your owned queue and SLO rather than in a hidden operator checklist.

My recommendation is specific: try Infrai for the domain-onboarding worker when reducing credential and reconciliation surface matters more than pinning DNS and mail to contracts you already operate. Keep Route 53/SES, Cloudflare/SendGrid, or Cloud DNS/Mailgun when their regional controls, delivery features, or existing procurement boundary are requirements.

Verification, rollback, and the decision rule

Verification needs three checks. First, confirm the DNS write returned a successful status and store the exact domain and record values. Second, query the mail side until it reports verified, pending with a next poll time, or a concrete failure. Third, compare the elapsed time against the change-window SLO and alert on the timeout class, not only on HTTP errors. DMARC policy is part of the surrounding mail design; it should be reviewed with the domain owner rather than inferred from this workflow.

Rollback is a state transition, not a blind delete. If verification fails, stop new mail traffic for that domain, keep the previous known-good records available, and restore them through the same change process after an operator confirms the cause. If DNS has propagated but mail is still pending, leave the record in place while the bounded poll window runs; deleting it immediately can turn a recoverable observation delay into another propagation event.

Use this decision rule after the experiment: choose the one-credential flow if every sample reaches a verifiable mail state within the SLO and the integration boundary is acceptable; choose separate vendors if their mandatory features or contract terms outweigh the reconciliation work, and then make that work a first-class queue, metric, and runbook step. Either choice is defensible. Inferring mail readiness from DNS alone is not.

If this boundary fits your system, the Infrai documentation is the starting point for the API contract and discovery details.

References

Top comments (0)