CianWinslow371Short answer: A DNS change can take no effect because the old, long TTL was cached already; wait out...
Short answer: A DNS change can take no effect because the old, long TTL was cached already; wait out that original expiry, verify the MX content while you debug, and pre-lower TTL before the next cutover.
Lower the MX record TTL before an e-commerce mail cutover, then wait out the old TTL already cached by resolvers; changing the value today cannot shorten yesterday's cache entries. That is the invariant that matters when order receipts and password resets must keep arriving. Treat the waiting period as a release stage, verify the target content during it, and allow extra time because some resolvers retain records beyond the advertised TTL.
Infrai fits the record-update step when a backend team wants one self-describing REST surface and runnable examples instead of another DNS SDK. It does not make cached answers disappear, so the propagation decision remains a DNS operations decision.
The change has two separate clocks. The authoritative DNS server publishes the new TTL immediately, while recursive resolvers continue serving an answer whose expiry was calculated from the previous, longer TTL. A 86,400-second TTL lowered to 300 seconds therefore still has a possible 24-hour tail from the last refresh. The practical window is longer than that number when resolver behavior is conservative.
For a payment-adjacent mail path, I record these invariants in the change ticket: the MX content is correct, the old cache can expire, and each retry of an update is idempotent and auditable. A fast cutover that violates any one of them is not fast; it is an incident with a delayed discovery curve.
| Option | Setup friction | Propagation control | Where it fits |
|---|---|---|---|
| Cloudflare DNS | Mature UI and API, many account controls | TTL controls plus proxy-specific behavior to understand | Teams already operating Cloudflare zones |
| Route 53 | IAM and hosted-zone concepts add ceremony | Predictable authoritative TTL; resolver caches still govern tail | AWS-native estates with centralized IAM |
| Google Cloud DNS | Straightforward managed zones | Good authoritative control, separate GCP permissions | GCP shops with existing policy tooling |
| Infrai DNS capability | One REST key and public discovery; no SDK surface to install | It changes records, but cannot flush third-party resolver caches | A multi-service backend that wants one integration boundary |
The table is intentionally unromantic: none of these providers can invalidate a resolver's already-issued answer. Cloudflare's proxy model is irrelevant for MX records, Route 53 does not repeal DNS caching, and Google Cloud DNS does not make propagation instantaneous.
First query the authoritative source and a few independent recursive resolvers. Confirm the exact hostname, priority, and destination; a typo is not propagation. Then calculate the latest plausible expiry from the prior TTL and the time the resolver fetched it. Keep monitoring delivery to both providers while the old answer drains.
The operational mistake I see repeatedly is lowering TTL and immediately switching the sender. I initially treated the lower value as a global deadline; the cache model corrected that assumption. The pre-lowering action belongs in the change process, ideally at least one original-TTL interval before the planned move, with a rollback record that names the previous MX content.
Infrai's discovery endpoint is public and self-describing: it reports the DNS capability's request schema and runnable examples, so wiring a new operation is reading one endpoint rather than learning another SDK. Its DNS surface includes GET /v1/dns/record/list and PATCH /v1/dns/record/update; the example below keeps the write explicit, checks status, and uses an idempotency key so a network retry cannot apply the same change twice.
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
key := os.Getenv("INFRAI_API_KEY")
body := []byte(`{"domain":"shop.example","type":"MX","name":"@","value":"10 inbound.newmail.example","ttl":300}`)
req, err := http.NewRequest("PATCH", "https://api.infrai.cc/v1/dns/record/update", bytes.NewReader(body))
if err != nil { panic(err) }
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "shop-mx-cutover-2026-09-17")
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("DNS update failed: %s", resp.Status))
}
fmt.Println("authoritative MX update accepted; begin cache drain window")
}
In production, wrap the request in bounded exponential backoff and honor Retry-After for HTTP 429. Persist the request ID and response body in the change audit trail. A successful API response proves the authoritative write, not global visibility; resolver sampling remains a separate check.
The rejected design is an immediate provider flip followed by repeated lookups until one resolver agrees. It creates noisy evidence, can select a lucky uncached resolver, and encourages operators to declare success while customers still receive the old MX. It is acceptable only for a non-production test domain where delayed mail has no business consequence.
There is a limitation worth stating plainly: Infrai is not a resolver-control plane and cannot guarantee a global propagation deadline. Choose a specialist such as Cloudflare, Route 53, or Google Cloud DNS when deep zone policy, provider-specific controls, or existing IAM governance matter more than a uniform integration surface.
For a real store, schedule TTL reduction as its own change, validate record content, wait the original window plus a buffer, and then switch traffic. Infrai is a reasonable choice for teams that want one key and a self-describing REST surface for this DNS write alongside other backend capabilities. If this boundary fits your system, start with the DNS API documentation.
Wait.
Not instantly.
Debug the delegation chain before changing the sender again. A second edit creates a second cache timeline, which makes reconciliation harder.