Nodemailer works locally. Then production happens.
Nodemailer fails silently in production, leaks memory from unclosed connections, and doesn't work on serverless. Ark sends email over HTTPS—clear errors, no connection pools, works on Vercel, Lambda, and Workers.
Nodemailer is a debugging nightmare
Works perfectly in development. Deploy to production and emails silently don't send. No errors, no logs, just... nothing. Then you discover SMTP ports are blocked on your host, or your connection pool is leaking sockets, or Gmail decided to stop accepting your auth.
- ×Silent failures in production—code works locally, nothing sends in prod
- ×Memory leaks from createTransport() without close()—sockets stay open forever
- ×Doesn't work on Vercel Edge, Cloudflare Workers, or any edge runtime (requires net, tls modules)
- ×Gmail authentication randomly stops working after months with no code changes
HTTP API instead of SMTP
Ark sends email over HTTPS. No SMTP ports to open, no connection pools to manage, no silent failures. Works on every platform—Node.js, Vercel, Lambda, Workers, Deno.
Replace Nodemailer in 2 minutes
npm install, set one environment variable, send. No createTransport, no SMTP config, no close() to forget.
Install the SDK
Works with Node.js 18+, Bun, Deno. Full TypeScript types included.
npm install ark-emailSet your API key
One environment variable. No SMTP host, port, secure, auth object.
# .env
ARK_API_KEY=ark_live_xxxxxxSend email
Three lines. Returns confirmation with message ID. Throws on error (no silent failures).
import { Ark } from "ark-email";
const ark = new Ark(); // Reads ARK_API_KEY from env
const { id } = await ark.emails.send({
from: "[email protected]",
to: "[email protected]",
subject: "Welcome!",
html: "<h1>You're in.</h1>",
});
console.log("Sent:", id); // Confirmed deliveryCode examples
Copy and paste to get started quickly.
// routes/email.ts
import { Ark } from "ark-email";
import { Router } from "express";
// No createTransport(), no pool config, no close() to forget
const ark = new Ark();
const router = Router();
router.post("/signup", async (req, res) => {
try {
const { id } = await ark.emails.send({
from: "[email protected]",
to: req.body.email,
subject: "Welcome to YourApp!",
html: "<h1>You're in!</h1>",
});
res.json({ emailId: id });
} catch (err) {
// Actual error—not silent failure
console.error("Email failed:", err.message);
res.status(500).json({ error: "Email failed" });
}
});
export default router;// app/api/welcome/route.ts
// Works on Vercel Edge—Nodemailer doesn't (requires net, tls modules)
import { Ark } from "ark-email";
export const runtime = "edge"; // Edge runtime—no Node.js modules
const ark = new Ark();
export async function POST(request: Request) {
const { email, name } = await request.json();
await ark.emails.send({
from: "[email protected]",
to: email,
subject: `Welcome, ${name}!`,
html: `<h1>Hi ${name}!</h1><p>Thanks for signing up.</p>`,
});
return Response.json({ sent: true });
}// src/index.ts
// Nodemailer can't run here—no net/tls. Ark uses fetch.
import { Ark } from "ark-email";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ark = new Ark({ apiKey: env.ARK_API_KEY });
const { email } = await request.json();
await ark.emails.send({
from: "[email protected]",
to: email,
subject: "Your alert triggered",
html: "<p>Something happened. Check it out.</p>",
});
return new Response(JSON.stringify({ sent: true }));
},
};What you can build
Production that actually sends
No more "works locally, silent in prod." Ark throws real errors and returns delivery confirmation. You'll know if email failed.
Serverless without workarounds
Vercel Edge, Lambda, Workers—all restrict SMTP ports or lack Node.js net/tls modules. Ark uses HTTPS on port 443. Works everywhere.
Long-running services without leaks
Nodemailer needs createTransport/close lifecycle. Miss a close() and sockets leak. Ark is stateless HTTP—nothing to close.
TypeScript-first development
Full type definitions. IDE autocomplete for every parameter. Catch bugs before runtime.
Why developers choose Ark
No silent failures
Ark throws on error and returns message ID on success. You always know what happened.
Works on edge and serverless
Uses fetch, not net/tls. Runs on Vercel Edge, Cloudflare Workers, Deno Deploy, and Lambda without SMTP port restrictions.
No memory leaks
Stateless HTTP requests. No connection pools to manage, no sockets to close, no createTransport() lifecycle.
Full TypeScript types
Built in TypeScript from day one. Every method, parameter, and response is typed. Your IDE knows everything.
What you get with Ark
Frequently asked questions
Why not just use Nodemailer?
Nodemailer works until it doesn't. It fails silently in production (you think email sent but it didn't), leaks memory if you forget close(), and doesn't work on edge runtimes or serverless platforms that block SMTP. Ark uses HTTPS, so it works everywhere and fails loudly.
Does this work on Vercel Edge Functions?
Yes. Nodemailer requires Node.js net and tls modules that don't exist on edge runtimes. Ark uses fetch over HTTPS—it works on Vercel Edge, Cloudflare Workers, Deno Deploy, and any edge runtime.
What about AWS Lambda?
Lambda often blocks SMTP ports or has strict network policies. Ark uses HTTPS on port 443, which is always allowed. No VPC configuration, no NAT gateway setup.
Do I need to manage connections?
No. Nodemailer requires createTransport() and close() to manage SMTP connections. Forget close() and you leak sockets. Ark is stateless HTTP—each send() is independent, nothing to manage or clean up.
Is there CommonJS support?
Yes. The SDK supports both ES modules (import) and CommonJS (require). Works with any Node.js project.
What does it cost?
$0.50 per 1,000 emails. No monthly fees. $2.50 welcome credit (5,000 emails). Most apps run for months on the free credit.
npm install ark-email
No Nodemailer. No silent failures. No memory leaks. Works on serverless. 2 minutes to first email.