Sending transactional email from Remix
Remix apps can deploy to Node or to edge runtimes (Cloudflare Pages, Deno Deploy), so the safest integration is fetch, which works identically across all of them, rather than a Node-specific SDK that might not run on an edge deploy target.
Send it from an action
Transactional sends belong in a Remix action (server-only code triggered by a form submission or mutation), never in a loader and never from client-side code, since both of those run in contexts where you either shouldn't be doing side effects (loaders) or would expose your API key (the client):
- export async function action({ request }: ActionFunctionArgs) { const res = await fetch('https://api.envello.dev/emails', { method: 'POST', headers: { Authorization: `Bearer ${process.env.ENVELLO_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ from, to, subject, html }) }); if (!res.ok) return json({ error: 'send failed' }, { status: 502 }); return json({ ok: true }); }
Environment variables across deploy targets
process.env works as expected on a Node deploy target. On Cloudflare Pages or other edge runtimes, environment variables typically come through a context object instead (context.env in Cloudflare's case), check your specific adapter's docs for exactly how secrets are exposed, since this is the one part of the integration that genuinely differs by deploy target even though the fetch call itself doesn't.