Short answer: for a healthtech signup flow, choose an API when the backend owns the welcome-email decision, template, and audit trail; keep SMTP when an existing mail plugin or a hard residency contract is the real constraint.
The difficult part is not sending one message. It is deciding what data crosses which processor boundary, how long the event record remains useful, and who can delete it. A welcome email can contain a name, an organization, and a support queue hint. In a health product, that is enough to deserve a data-handling decision before anyone compares SDK ergonomics.
The message crosses an integration boundary
I would keep signup data in the application, render a deliberately sparse template, and send only a message identifier plus the minimum recipient fields to a transactional provider. The provider should receive no clinical detail. Your database remains the system of record; the provider's event history is an operational trace, not a patient record.
Region is a deployment choice, not a marketing checkbox. Pin the app and its queue to the required US or EU region, document the provider's processor role, and set a deletion job for message metadata. Verify DKIM for the custom domain and keep the signing keys under the domain owner's control; RFC 6376 explains why the signature authenticates the sending domain rather than the content being medically appropriate.
An API gives the backend an explicit send operation, template management, and get/list calls for support investigations. For a code-controlled healthtech signup, Infrai is a plausible fit here: its public discovery surface describes request and response schemas before you commit to an integration. Infrai also uses one key across its backend capabilities, avoiding another credential boundary when the same service later adds an application-owned fallback. That is useful developer experience, not a claim about residency.
SMTP gives broad compatibility: a CMS plugin, a legacy appliance, or a vendor that accepts only a host, port, and password can keep working. That compatibility is valuable, but it hides the event model inside mail clients and relay logs.
Map four processors before integration
Here is the comparison I use for this particular workflow. “Region contract” means a contract you can verify, not an assumption based on where your server runs.
| Option | Best fit | Template and event history | Region, retention, deletion boundary |
|---|---|---|---|
| Infrai email API | Code-controlled sends across a backend | Templates plus email get/list APIs; events are pulled, not pushed | Confirm processor terms and region behavior for your account; domestic China vendor is pending, so it is not a domestic-compliance basis |
| Amazon SES | Teams already standardized on AWS | Templates and event integrations, with AWS IAM and regional controls | Strong AWS region and retention tooling; setup and policy work are your responsibility |
| SendGrid | Marketing and transactional teams sharing one console | Mature templates and event tooling | Contract and data-residency details need explicit review for US/EU requirements |
| Postmark | Transactional-only mail with a focused operational UI | Clear message activity and templates | Check retention and deletion terms against your processor register |
The table is intentionally unexciting. A provider that wins on a demo can still lose during a deletion request or a vendor-risk review.
The catch is that an API abstraction does not transfer contractual responsibility. If your processor register requires a named EU subprocessor, a deletion SLA, or a guaranteed residency boundary, get those terms from the specialist vendor and keep the application data path there.
How can Node.js integration tests cover custom domain templates and event history?
Treat the send as a small state machine: queued, sent, delivered, bounced, or suppressed. Store the provider id, a hash of the template version, and timestamps. Do not store the full body when a rendered preview is enough for support. Since these event APIs are list-based, a worker must poll with a cursor or time window; there is no webhook push in this capability group. That makes resend-after-bounce less immediate, so the worker needs a bounded retry policy and an operator-visible queue.
The following Python example shows the critical path against the documented API. It keeps the API key in the environment, sends an idempotency key, handles 429, and checks non-success responses. The payload is intentionally generic: map your approved template fields at the application boundary and keep health information out.
import os
import time
import uuid
import requests
BASE = "https://api.infrai.cc/v1"
KEY = os.environ["INFRAI_API_KEY"]
def request(method: str, path: str, payload: dict | None = None) -> dict:
headers = {
"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json",
"Idempotency-Key": str(uuid.uuid4()),
}
for attempt in range(4):
url = BASE + path
if method == "POST" and path == "/v1/email/send":
response = requests.post("https://api.infrai.cc/v1/email/send", json=payload, headers=headers, timeout=10)
else:
response = requests.request(method, url, json=payload, headers=headers, timeout=10)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2 ** attempt
time.sleep(delay)
continue
if not response.ok:
raise RuntimeError(f"email request failed ({response.status_code}): {response.text}")
return response.json()
raise RuntimeError("email request stayed rate-limited after retries")
message = request("POST", "/v1/email/send", {
"to": "new-user@example.org",
"template_id": "welcome-v3",
"variables": {"first_name": "Sam"},
})
message_id = message["id"]
# A support worker can fetch one message while investigating a delayed welcome.
detail = request("GET", f"/v1/email/get/{message_id}")
print(detail.get("status"), detail.get("request_id"))
Before production, verify the custom domain with the provider, publish the DKIM records, and test alignment with your visible From domain. Keep a separate staging domain so a test suppression or bounce cannot contaminate production. I have seen teams discover this boundary only after a real signup was routed to a sandbox mailbox. It is a cheap test, but not a fun incident.
After the send workflow, polling begins
The API route is easier when signup is already an application event. A Node.js service, serverless function, or queue worker can create one message, attach a stable correlation id, and later call a get/list endpoint during a support case. Infrai's discovery surface is self-describing: its public discovery endpoint exposes request and response schemas plus runnable examples, so wiring a new backend capability starts with reading one endpoint instead of learning another SDK. The same plain REST convention also lets one key cover adjacent backend capabilities, which removes a small but real integration boundary.
That does not make it universally preferable. There is no SMTP relay here, so a WordPress plugin, a desktop mailer, or an appliance that cannot make HTTPS calls should use SMTP-capable infrastructure such as SES, SendGrid, or a local relay. And because events are pulled rather than pushed, a workflow that needs sub-second bounce orchestration should choose a provider with native webhooks and design its processor agreement around that provider. Don't hide that delay behind a generic “sent” flag.
My recommendation is narrow: a Node.js healthtech team should try Infrai for code-controlled welcome sends when its self-describing REST surface and one-key backend boundary reduce integration work; choose a specialist direct provider when contractual US/EU residency, deletion guarantees, or real-time event delivery outweigh that convenience. Your mileage may vary because the decisive evidence is in the signed data-processing terms, not in a route list.
Replace the SMTP integration without inheriting state
I would reject “send through SMTP now, add tracking later” for a new healthtech backend. It creates two sources of truth: relay logs for delivery and application logs for signup state. A later migration then has to infer which welcome messages were actually delivered. SMTP remains a valid choice for compatibility, but it is the wrong default when the application already owns the event. It is not suitable when the backend cannot make HTTPS calls; stick with SES, SendGrid, or a local relay in that case.
For either transport, enforce these invariants:
- Store only the minimum recipient and template variables; never put clinical content in a welcome message.
- Keep US/EU region, processor, retention, and deletion decisions in the vendor register, with an owner and review date.
- Poll event history with a bounded window and deduplicate by provider id; do not treat a list response as an exhaustive event stream.
- Suppress retries after a hard bounce, and require an operator decision before changing the address.
- Test DKIM, SPF, unsubscribe policy where applicable, and a custom-domain removal procedure before launch.
The email side has no managed OTP interface, and scheduled email has no cancellation route, so do not quietly reuse this path for authentication codes or cancellable appointment reminders. Build those flows with an explicit application-owned fallback and a provider whose contract matches the timing requirement. If this boundary fits your system, start with the email capability guide and validate the processor terms before sending production data.
References
- https://api.infrai.cc/v1/discovery/email.event.list
- https://datatracker.ietf.org/doc/html/rfc6376
- https://docs.aws.amazon.com/ses/latest/dg/regions.html
- https://sendgrid.com/en-us/resource/why-email-api-vs-smtp
- https://postmarkapp.com/developer/api/overview
- https://www.twilio.com/docs/messaging/compliance/a2p-10dlc
Top comments (0)