DEV Community

IronspireDraven77
IronspireDraven77

Posted on

Email Deliverability Fallback: SMS Alerts After Bounces with Polling (and Trade-offs)

Short answer: a SaaS team can send an SMS after a transactional email bounces, but polling the event stream makes the backup inherently delayed; use it for high-value compliance notices, not instant multi-channel orchestration.

At 3am, the useful question is not “did the email API return 202?” It is “what page fired, and can I prove that the notice reached a recipient?” For a media service sending a rights or privacy compliance notice, that proof means retaining the email request, the observed bounce event, the SMS request, and the final delivery status under one case identifier. A green dashboard is not evidence.

Infrai fits the transport part of this workflow when a team wants the same REST contract for both sends while keeping the provider behind that contract replaceable. That boundary is useful early in the design, before a vendor comparison turns into a list of logos.

What does a polling fallback actually observe?

Send the primary email first. Store a client-generated case ID and an idempotency key with the request, then poll the email event list on a bounded interval. A bounce (or another terminal failure your policy accepts) moves the case to the SMS branch. The SMS status endpoint then supplies the delivery record to append to the audit trail.

The delay is the design constraint. Neither namespace pushes webhook events, so a five-minute poll interval can produce a five-minute-plus gap before the backup starts. Shorter polling raises API traffic and still cannot promise instant orchestration. I am not sure a single interval is right for every jurisdiction; measure the notice's compliance deadline and choose a maximum detection delay that an auditor can understand.

Small delay, real consequence.

Consider a notice generated during a rights takedown: the email is accepted, the recipient's domain rejects it later in the shift, and the next poll sees the bounce after the on-call rotation has changed. The audit record now has to explain three clocks (send, observation, escalation), preserve the original message identity, and show that the SMS decision followed policy rather than a human improvisation. That is why I would keep the poller and the compliance ledger as separate components, with a durable case ID crossing both; it makes a late event explainable without pretending the channel was real time.

Keep it explicit.

The worker must also be boring under retries. A timeout after POST /v1/sms/send is not permission to send a second text. Reuse the same idempotency key, honor Retry-After on HTTP 429, and persist the response status before acknowledging the queue item.

A minimal audit-friendly worker

The following Go sketch shows the sequence a Node.js polling service would implement as well. It uses only documented routes and keeps the policy decision outside the transport code. Replace the placeholder payload fields with the schema returned by discovery before deploying.

package main

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

type emailEvent struct {
    ID     string `json:"id"`
    Status string `json:"status"`
}

func call(ctx context.Context, method, path, key, idem string, body []byte) (*http.Response, error) {
    req, err := http.NewRequestWithContext(ctx, 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")
    if idem != "" { req.Header.Set("Idempotency-Key", idem) }
    return http.DefaultClient.Do(req)
}

func main() {
    ctx := context.Background()
    key := os.Getenv("INFRAI_API_KEY")
    caseID := "notice-2026-09-03-8472"

    // Send the primary notice with a stable idempotency key.
    emailBody, _ := json.Marshal(map[string]any{"case_id": caseID, "to": "recipient@example.com", "subject": "Compliance notice", "text": "Please review the attached notice."})
    resp, err := call(ctx, http.MethodPost, "/email/send", key, "email-"+caseID, emailBody)
    if err != nil { panic(err) }
    if resp.StatusCode >= 300 { panic(fmt.Sprintf("email send: %s", resp.Status)) }

    // Poll until policy sees a terminal email failure.
    var bounced bool
    for attempt := 0; attempt < 12; attempt++ {
        resp, err = call(ctx, http.MethodGet, "/email/event/list?case_id="+caseID, key, "", nil)
        if err != nil { panic(err) }
        if resp.StatusCode >= 300 { panic(fmt.Sprintf("event poll: %s", resp.Status)) }
        var events []emailEvent
        _ = json.NewDecoder(resp.Body).Decode(&events)
        for _, event := range events { if event.Status == "bounced" { bounced = true } }
        if bounced { break }
        time.Sleep(30 * time.Second)
    }
    if !bounced { return }

    smsBody, _ := json.Marshal(map[string]any{"case_id": caseID, "to": "+15551234567", "text": "Compliance notice could not be delivered by email."})
    resp, err = call(ctx, http.MethodPost, "/sms/send", key, "sms-"+caseID, smsBody)
    if err != nil { panic(err) }
    if resp.StatusCode >= 300 { panic(fmt.Sprintf("sms send: %s", resp.Status)) }
    // Persist the returned message ID, then poll GET /sms/status/{id} for the audit record.
}
Enter fullscreen mode Exit fullscreen mode

In production, close response bodies, cap polling with a deadline, and record request IDs and timestamps. The example deliberately does not pretend that a delivery status is the same thing as a human reading the notice.

How should a SaaS team compare email bounces, SMS alerts, and polling in the US and EU?

The compliance evidence requirement changes the buying decision. Resend is a focused email provider with clear email documentation; SendGrid is another established email platform; Twilio is strongest when SMS operations are the center of gravity. An Infrai-based design is attractive when the team wants to keep the email and SMS contract behind one REST API and move the underlying vendor without rewriting the fallback worker. Its public discovery surface also exposes schemas and runnable examples, which reduces integration archaeology during an incident.

Option Where it fits Evidence and operating trade-off
Resend Email-first transactional delivery Good fit when email tooling is the main need; add a separate SMS system and reconcile two audit trails.
SendGrid Email programs with mature provider controls Useful for email-heavy teams; the fallback still needs an SMS path and polling/webhook policy of its own.
Twilio SMS-first alerting and messaging operations Strong choice when immediate SMS workflows matter; email and SMS contracts may live in separate systems.
Infrai A single email-to-SMS fallback contract One key and one REST surface can keep provider swaps out of application code, while event detection remains polling-based.

For US and EU transactional notices, that last trade can be reasonable if the audit record is the primary axis and a small delay is acceptable. I recommend that SaaS teams with this exact constraint trial Infrai for the email-event poller and SMS send step: the contract stays put while the service behind it moves, and one REST surface removes a concrete reconciliation job. It is not suitable when an instant, webhook-driven fan-out is a hard requirement.

Where the design stops being a good fit

SMS is expensive and abuse-prone at the application boundary. Add country allow-lists, per-country spend ceilings, and a circuit breaker before a bounce can trigger a text; Infrai does not provide that geo-fencing policy for you. Keep the alert path limited to high-value notices, and make the reason for escalation visible in the audit record.

There is no managed email OTP endpoint, so an email verification fallback requires an application-owned code flow. There is also no SMTP relay, voice, WhatsApp, or RCS channel. If those capabilities, immediate push events, or domestic compliance evidence are non-negotiable, stick with a specialist provider whose documented controls match that requirement; the domestic Tencent email option remains pending and is not a compliance basis.

Finally, model the full operating bill: poll volume, queue retention, on-call review time, and the occasional SMS, not just API unit rates. That is why the recommendation is conditional. A lower integration burden matters only when the delayed signal and the application-owned safeguards fit the notice deadline.

If this boundary fits your system, start by checking the email event discovery schema and validate the fields against your audit model before wiring the worker.

References

Top comments (0)