@ingram-tech/nk-email
v0.3.1
Published
Zero-dependency Cloudflare Email Sending client for Ingram Technologies Next.js projects.
Readme
@ingram-tech/nk-email
Zero-dependency Cloudflare Email Sending client — the one shared email client for Ingram sites.
Install
bun add @ingram-tech/nk-emailEnvironment
This package owns its own env contract (see src/keys.ts):
| Variable | Description |
| --- | --- |
| CLOUDFLARE_ACCOUNT_ID | Account that owns the sending domain |
| CLOUDFLARE_EMAIL_API_TOKEN | Token with Email Sending permission |
| EMAIL_FROM_DOMAIN | Verified sending domain, e.g. mail.example.com |
Use
import { sendEmail, fromAddress } from "@ingram-tech/nk-email";
await sendEmail({
to: "[email protected]",
from: fromAddress("Malina More Studio", "hello"),
replyTo: "[email protected]",
subject: "Your booking is confirmed",
html: "<p>See you Saturday!</p>",
text: "See you Saturday!",
});Supports cc, bcc, attachments, and custom headers.
One-click unsubscribe (RFC 8058)
Any non-transactional send — a newsletter issue, a post-signup lifecycle nudge —
must carry List-Unsubscribe headers for Gmail/Yahoo bulk-sender compliance and
deliverability. Pass listUnsubscribe and the header pair is generated for you:
await sendEmail({
to: "[email protected]",
from: fromAddress("Acme", "news"),
subject: "What's new",
html,
text,
listUnsubscribe: {
url: "https://acme.com/u?token=…", // one-click POST target, unauthenticated + idempotent
mailto: "[email protected]", // optional fallback
},
});The standalone buildListUnsubscribeHeaders({ url, mailto }) is exported for
callers that assemble headers themselves. For the full subscription / lifecycle
machinery (contacts, consent, dedup, rendering) reach for
@ingram-tech/nk-marketing, which builds on this.
Escaping
escapeHtml(value) escapes the five HTML-significant characters — use it when
interpolating any user-controlled text into an HTML email body.
Fail fast / degrade gracefully
import { keys, isConfigured } from "@ingram-tech/nk-email";
keys(); // throws listing every missing env var — call at startup
isConfigured(); // boolean — skip sending in local/dev instead of throwingDesign
- Zero dependencies beyond
fetch. No SDK, no Node-only APIs — runs on Vercel Functions, the edge, or anywherefetchexists. fromis required and explicit. Build it withfromAddress()so the sender domain comes fromEMAIL_FROM_DOMAIN, never hard-coded.
