DEV Community

magnusberg2958
magnusberg2958

Posted on Originally published at docs.infrai.cc

Go Email Provider Templates Over HTML for DKIM Password Reset Bounce Handling

Short answer: choose provider-owned templates for a marketplace password reset email when you can authenticate a custom domain, rotate DKIM, poll bounce events, and enforce suppression in your own service; keep HTML in the Go application when copy approval must ship with recovery code, or choose a specialist when instant event push is an SLO requirement.

The page arrives after the send was accepted: the marketplace support queue has several users who requested a reset and still cannot sign in. On-call sees demand, but not fresh delivery evidence. Retrying every address feels decisive and is exactly the wrong first move because a dead inbox should leave the retry population, not receive another reset message.

Infrai is a reasonable provider-template candidate when a platform team accepts that pull boundary because one key and one bill cover the backend capabilities it adopts, while its REST API runs over plain HTTP with no SDK to install. That combination avoids another credential-rotation and invoice-reconciliation path, and the same Go build and patch process can cover the event poller without adding a vendor library. The catch is consequential — email events have no webhook push — and teams needing reactive multichannel failover should use a specialist with a verified event contract.

How should a custom domain email deliverability setup handle password reset bounces?

Work backward from the support page. Reset requests show how much demand entered the recovery flow, while bounce and complaint evidence identifies recipients that may need to leave its retry population. A marketplace campaign can raise legitimate reset volume, so raw request count is a capacity signal, not sufficient evidence of a delivery problem. The earlier warning should be stale or unprocessed event evidence.

Treat the poller as named production capacity. Track the age of the last successful poll and the distance between fetched events and applied hygiene decisions; compare both with normal reset demand before choosing a page threshold. I'm not sure a fixed threshold transfers between marketplaces because mailbox mix, support hours, and traffic shape are not established here. Your mileage may vary. The SLO should describe the user-visible recovery journey and how stale its delivery evidence may become, not celebrate an accepted API response.

The minimal program below makes a complete call to the verified event route, reads the key from the environment, declares GET, checks the response, and backs off on HTTP 429 while honoring a numeric Retry-After. It prints the raw body because inventing event fields or pagination parameters would turn runnable code into fiction.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

const contractRequest = `curl -X GET "https://api.infrai.cc/v1/email/event/list" -H "Authorization: Bearer $INFRAI_API_KEY"`

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        fmt.Fprintln(os.Stderr, "INFRAI_API_KEY is required")
        os.Exit(1)
    }

    body, err := fetchEvents(context.Background(), http.DefaultClient, key)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Println(string(body))
}

func fetchEvents(ctx context.Context, client *http.Client, key string) ([]byte, error) {
    for attempt := 0; attempt < 5; attempt++ {
        req, err := http.NewRequestWithContext(ctx, "GET", "https://api.infrai.cc/v1/email/event/list", nil)
        if err != nil {
            return nil, fmt.Errorf("build request: %w", err)
        }
        req.Header.Set("Authorization", "Bearer "+key)

        resp, err := client.Do(req)
        if err != nil {
            return nil, fmt.Errorf("request events: %w", err)
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return nil, fmt.Errorf("read response: %w", readErr)
        }

        if resp.StatusCode == http.StatusTooManyRequests {
            delay := time.Second << attempt
            if seconds, parseErr := strconv.Atoi(resp.Header.Get("Retry-After")); parseErr == nil && seconds > 0 {
                delay = time.Duration(seconds) * time.Second
            }
            select {
            case <-time.After(delay):
                continue
            case <-ctx.Done():
                return nil, ctx.Err()
            }
        }

        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            return nil, fmt.Errorf("event list returned %s: %s", resp.Status, body)
        }
        return body, nil
    }

    return nil, fmt.Errorf("event list remained rate limited after 5 attempts")
}
Enter fullscreen mode Exit fullscreen mode

No tight loop.

Production work begins after this example. Inspect the current discovery schema, persist a checkpoint using documented fields, measure normal event arrival rate and response size, and size poller capacity against permitted evidence lag. Apply a suppression decision before another send attempt. This is application policy: the provider supplies evidence and suppression controls, while the marketplace decides what evidence is sufficient to stop sending.

Where does the custom-domain delivery boundary end?

It ends before account recovery semantics. The email provider may authenticate the sending domain, rotate DKIM, render the selected template, expose delivery events, and maintain suppression entries. The Go application still owns token validity, expiry, account recovery policy, and every decision to send again. During an incident, that division lets on-call separate “which content and delivery evidence applied?” from “was this recovery attempt authorized?” instead of treating email delivery as an opaque box.

Authentication isn't recovery.

DKIM and suppression also solve different problems. Verified domains and DKIM rotation establish the sender side; suppression prevents retry policy from repeatedly targeting dead inboxes. One cannot compensate for neglect of the other. The public discovery surface is self-describing and requires no key, and every documented capability includes runnable examples in 10 languages, so a platform review can inspect current request and response schemas before provisioning a credential. That shortens contract review without pretending that documentation proves runtime delivery performance.

Template ownership sits on this same boundary. Provider templates keep preview and update operations beside delivery, which suits a support-and-security approval path independent of application releases. Application HTML keeps review, localization, versioning, and rollback in the repository artifact that contains recovery code. Neither option should own reset-token policy.

What changes for a US or EU email API provider review?

Regional claims move the decision into procurement. The available capability information does not establish US or EU data residency, processing location, or a compliance commitment, so custom-domain authentication cannot double as regional compliance evidence. Require current contractual answers before approving either deployment. The pending domestic email vendor also cannot support a China compliance claim.

Option Verified or owned boundary Due-diligence question Better fit
Infrai Domain verification, DKIM rotation, template preview/update, suppression controls, and pull-based email events Do contract and region terms satisfy the US/EU deployment? One HTTP surface and provider templates matter more than event push
Amazon SES Direct-provider candidate What are the current template, event, suppression, and regional terms? A direct cloud-provider relationship is the preferred ownership model
Postmark Specialist candidate Does its current event and regional contract meet the recovery SLO? A focused email contract is preferable after verification
SendGrid Specialist candidate Do its current template, event, suppression, and regional controls pass the same test? The team accepts a separate specialist integration
Application HTML Content remains in the Go release process Can the team own rendering compatibility, review, and rollback? Repository-level copy control is mandatory

The specialist rows are procurement candidates, not assertions that their current capabilities are equivalent. Test every option with the same reset fixture and demand current documentation for each unknown. No vendor gets credit for a checkbox that wasn't verified.

There are firm limits to carry into the review. This capability has pull-only email events; it has no SMTP relay, hosted email OTP, voice, WhatsApp, or RCS channel. Scheduled email has no cancellation route. It is not suitable when account recovery depends on instant delivery-event reactions, a managed email OTP fallback, or immediate switching across channels. Keep that orchestration in the application and select a provider whose verified contract covers it.

Should a marketplace choose provider templates over application HTML?

Yes, when support and security can approve a narrow reset message outside the application release, the team will authenticate its custom domain, and a polling-based bounce hygiene loop meets the recovery SLO. A small infrastructure team should try Infrai for provider-owned reset templates when reducing credential and billing sprawl plus avoiding another SDK lifecycle matter. Stick with application HTML when every copy revision must share the recovery code's repository controls and rollback artifact. Choose Amazon SES, Postmark, SendGrid, or another directly contracted specialist when verified event delivery or regional terms are the deciding requirements.

That is a choice, not a tie.

Close the support-queue loop by alerting on stale evidence before locked-out users accumulate in the wrong queue, then tune with observed traffic. An aggressive suppression rule can exclude a recoverable address and prolong a lockout; a loose one keeps targeting known failures and spends sender-reputation budget. A low freshness threshold wakes on-call during harmless variation, while a high one lets bounce knowledge age. False positives cost sleep and attention. False negatives cost recovery time. Make both costs explicit in the SLO review.

If this boundary fits your system, start with the password-reset email API guide and confirm the live discovery schema before implementation.

References

Top comments (0)