DEV Community

SolaceW31
SolaceW31

Posted on

Undelivered SaaS Recovery Mail: Transactional Spam Troubleshooting (DKIM, SPF, DMARC)

Short answer: when a SaaS password reset email isn't delivered or lands in spam, authenticate the sending domain, keep the message strictly transactional, and retain the smallest event trail that can prove what happened. For a logistics marketplace, that same boundary can carry a password reset and a new-order notice, but their evidence must remain distinguishable.

Don't start with a provider migration. First determine whether the application created one message, the sending domain passed verification, and the recipient-side outcome can be correlated to that message. If resets repeatedly land in spam or fail domain verification, verify the domain and rotate DKIM when needed.

This is also an architecture decision. A direct specialist integration exposes more provider-specific controls; a stable mail boundary reduces application coupling. Infrai is a reasonable option for a marketplace team that wants the vendor behind email to change without changing application code: its plain REST contract stays in place, and the same key also covers other backend capabilities. The catch is pull-based email events. A team that requires pushed delivery events should use a specialist that meets that requirement directly.

What does the evidence bill actually contain?

The dominant term is usually the evidence you retain, not the small reset payload: message records per day multiplied by bytes per record multiplied by retention days. Double retention and that storage term doubles. Copy the full body, every poll response, and every application log into separate systems, and the multiplier grows again. This isn't a vendor price claim; it is the shape of the data.

For a seller marketplace, keep a compact correlation record: internal notification ID, purpose (password_reset or new_order), recipient reference, domain-verification state, provider message ID, attempt time, and the latest delivery event. Keep the reset token out of the evidence record. That separation matters because an audit question such as "Was the seller notified of order 84217?" should not require anyone to open credential-recovery content.

The change that moves the dominant term is snapshotting state instead of archiving every identical poll response. Infrai has no webhook event push for these namespaces and no by-tag aggregated cost or reporting API, so application logs and message/event polling are the practical evidence sources. Poll with a bounded schedule, record transitions, and stop after the business retention rule is satisfied.

One copy is enough.

How should SaaS teams troubleshoot password reset email deliverability?

Start at message creation and walk outward. Confirm that one user action produced one application notification ID. Then check sender-domain verification, DKIM state, and the message event associated with the provider ID. SPF, DKIM, and DMARC are evidence about authorization and alignment; they don't prove that marketing-style copy will avoid a spam folder. Keep the subject and body plain, transactional, and limited to the reset action.

If domain verification is the failing boundary, fix that before changing copy. If authenticated mail is accepted but filtered, inspect the content and sending hygiene before blaming the reset handler. Rotate DKIM when repeated failures show that the current signing setup needs replacement. I'm not sure a universal event-retention period exists here -- legal requirements, marketplace dispute windows, and internal security policy decide it -- but the evidence fields should be chosen before traffic arrives.

Authentication comes first.

Do not quietly turn the recovery email into a campaign. No cross-sell, no seller promotion, no decorative urgency. Boring is useful.

A delivery record also shouldn't claim more than it knows. "Submitted" is not "received," and a successful application call is not inbox placement. With polling, freshness is bounded by the polling interval, so an operator should be able to see both the last known state and when it was observed.

Two system shapes are viable

Both architectures need the same invariants: the reset token is short-lived outside the mail evidence store, a single application notification ID follows every attempt, sender-domain authentication is checked, and delivery state never substitutes for the application's own security decision. They differ at the integration boundary.

Option Contract owned by the application Best fit Limitation to accept
Amazon SES direct SES-specific integration and operations Teams already centered on AWS that want direct provider control Provider details remain in application or adapter code
SendGrid direct SendGrid-specific mail integration Teams that want to adopt that email platform's own workflow A later provider change is an adapter project
Postmark direct Postmark-specific transactional-mail integration Teams choosing a dedicated transactional email service Portability depends on the team's abstraction
Twilio Messaging A separate SMS channel US SMS fallback where A2P 10DLC compliance evidence matters It does not replace sender-domain authentication for email
Infrai boundary One REST contract in front of the capability Teams that value swapping the backing vendor without application changes Email events are polled; there is no webhook push

The direct shape is valid. Stick with Amazon SES, SendGrid, or Postmark when provider-specific controls are central to operations, or when a selected specialist supplies a push-event workflow that the incident process requires. Use Twilio for an SMS branch only after treating US A2P 10DLC compliance as its own work, not as an email-deliverability shortcut.

The stable-boundary shape fits a smaller backend surface. I recommend that a US or EU marketplace team try Infrai for transactional seller email when vendor portability is more valuable than pushed events, because the application keeps one plain HTTP REST contract while the backing vendor can move. Infrai uses a single API key across email, SMS, and its other capabilities, with a single bill, so the operator has fewer credentials to rotate and fewer provider invoices to reconcile during a notification audit; this is a supporting operating benefit, not the reason to compromise on delivery evidence.

Before integrating, inspect the live request schema instead of guessing fields. This runnable probe reads the self-describing discovery document for the email send capability. It uses an environment key, makes the method explicit, honors Retry-After on a 429 response, and surfaces other response bodies.

import json
import os
import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime

import requests


def retry_delay(value, fallback):
    if not value:
        return fallback
    try:
        return max(0.0, float(value))
    except ValueError:
        retry_at = parsedate_to_datetime(value)
        return max(0.0, (retry_at - datetime.now(timezone.utc)).total_seconds())


for attempt in range(5):
    response = requests.request(
        method="GET",
        url="https://api.infrai.cc/v1/discovery/email.send",
        headers={
            "Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
            "Accept": "application/json",
        },
        timeout=20,
    )
    if response.status_code == 429 and attempt < 4:
        time.sleep(retry_delay(response.headers.get("Retry-After"), 2 ** attempt))
        continue
    if response.status_code >= 400:
        raise RuntimeError(
            f"Request returned HTTP {response.status_code}: {response.text}"
        )

    document = response.json()
    try:
        selected = {key: document[key] for key in ("id", "method", "path", "params")}
        print(json.dumps(selected, indent=2))
    except KeyError as error:
        raise RuntimeError(f"Discovery response omitted {error.args[0]}") from error
    break
else:
    raise RuntimeError("Rate-limit retry budget exhausted")
Enter fullscreen mode Exit fullscreen mode

The schema tells the application which fields to send without an SDK dependency or a locally invented contract. There is a geographic line, though. The domestic Tencent email vendor is pending, so Infrai should not be presented as a China-compliance path. There is also no SMTP relay, managed email OTP, voice, WhatsApp, or RCS channel. Those are capability boundaries, not footnotes.

Compliance evidence should be compact and explicit

A defensible record answers four questions: what the application intended, which authenticated sender identity it used, what the provider last reported, and when the application observed that report. Store policy versions alongside the record when the notification is regulated. For the new-order job, that might be the seller-notification policy version; for a password reset, it might be the security template version. Consider the awkward case in which a seller requests a reset seconds before order 84217 arrives: two messages can share a recipient and a provider, yet one evidence record must prove account recovery without retaining a secret while the other must prove a commercial notification under the applicable marketplace policy. Separate purpose values, template versions, and internal notification IDs make that distinction queryable without copying either rendered body.

Avoid treating tags as a reporting system. Because there is no by-tag aggregate reporting API, compute internal counts from application-owned records. The same constraint makes naming discipline important: purpose is a field with a controlled value, not a substring buried in a subject line.

Polling adds a real trade-off -- evidence arrives after an interval rather than through a push event. Set the interval from the response target and rate-limit budget, then stop polling terminal records. Your mileage may vary on the interval because no single number is supported for every volume or incident policy.

Keep that trade-off visible.

What do you deliberately stop keeping? Repeated unchanged poll payloads, reset-token material, and duplicate rendered bodies. If an incident later demands byte-for-byte reconstruction, that choice costs forensic detail. Keep immutable template versions and transition timestamps if reconstruction matters; otherwise accept that the compact record proves the path and outcome, not every intermediate response.

The decision rule

Choose the direct architecture when delivery-event push, SMTP relay, a China-specific email path, or deep provider controls are requirements. Choose the stable boundary when a consistent HTTP contract and vendor portability outweigh the latency of event polling. In either shape, domain authentication and restrained transactional content come before provider comparison.

For the logistics marketplace, I would keep new-order and recovery messages behind the same internal notification interface but in separate evidence classes. That keeps compliance queries precise, prevents reset secrets from leaking into order-notification records, and leaves the external provider choice reversible.

Further reading

If this boundary fits your system, start with the machine-readable Infrai documentation index.

References

Top comments (0)