No SDK Required
Most email APIs require you to install an SDK. With SMTPfast, you use the built-in fetch() API that ships with Node.js 18+. No packages to install, no dependencies to maintain.
Prerequisites
- Node.js 18 or later (for built-in
fetch) - An SMTPfast account with a verified domain
- An API key from the SMTPfast dashboard
Send Your First Email
Create a file called send-email.js:
async function sendEmail() {
const res = await fetch("https://smtpfa.st/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMTPFAST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "[email protected]",
to: "[email protected]",
subject: "Welcome to our app!",
html: "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(`Email send failed: ${error.message}`);
}
const { id } = await res.json();
console.log("Email sent! ID:", id);
return id;
}
sendEmail();
Run it:
SMTPFAST_API_KEY=sf_your_api_key node send-email.js
That is it. No npm install, no configuration files.
Add Error Handling
In production, you want proper error handling and retries:
async function sendEmail(to, subject, html, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const res = await fetch("https://smtpfa.st/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMTPFAST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ from: "[email protected]", to, subject, html }),
});
if (res.status === 429) {
// Rate limited - wait and retry
const retryAfter = parseInt(res.headers.get("retry-after") || "1");
await new Promise((r) => setTimeout(r, retryAfter * 1000));
continue;
}
if (!res.ok) {
const error = await res.json();
throw new Error(error.message);
}
return await res.json();
} catch (err) {
if (attempt === retries) throw err;
// Exponential backoff
await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 100));
}
}
}
Build a Reusable Helper
Wrap the API in a simple module you can import anywhere:
// lib/email.js
const SMTPFAST_URL = "https://smtpfa.st/api/v1/emails";
async function send({ from, to, subject, html, text, replyTo, tags }) {
const res = await fetch(SMTPFAST_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMTPFAST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from,
to,
subject,
html,
text,
reply_to: replyTo,
tags,
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(`SMTPfast error: ${error.message}`);
}
return res.json();
}
module.exports = { send };
Use it in your app:
const email = require("./lib/email");
// Welcome email
await email.send({
from: "App <[email protected]>",
to: user.email,
subject: "Welcome to our app!",
html: `<h1>Welcome, ${user.name}!</h1>`,
});
// Password reset
await email.send({
from: "Security <[email protected]>",
to: user.email,
subject: "Reset your password",
html: `<p>Click <a href="${resetLink}">here</a> to reset your password.</p>`,
tags: [{ name: "type", value: "password-reset" }],
});
Use with Express
Here is a common pattern for sending emails from an Express route:
const express = require("express");
const email = require("./lib/email");
const app = express();
app.use(express.json());
app.post("/api/invite", async (req, res) => {
const { inviteeEmail, teamName } = req.body;
try {
const { id } = await email.send({
from: `${teamName} <[email protected]>`,
to: inviteeEmail,
subject: `You're invited to join ${teamName}`,
html: `<p>Click <a href="https://yourapp.com/invite/${inviteToken}">here</a> to join.</p>`,
});
res.json({ success: true, emailId: id });
} catch (err) {
console.error("Failed to send invite email:", err);
res.status(500).json({ error: "Failed to send invitation" });
}
});
Check Delivery Status
After sending, you can check whether the email was delivered:
async function checkEmailStatus(emailId) {
const res = await fetch(`https://smtpfa.st/api/v1/emails/${emailId}`, {
headers: {
Authorization: `Bearer ${process.env.SMTPFAST_API_KEY}`,
},
});
const data = await res.json();
console.log("Status:", data.last_event); // "delivered", "bounced", etc.
return data;
}
TypeScript Version
If you are using TypeScript, here is a typed version of the helper:
interface SendEmailOptions {
from: string;
to: string | string[];
subject: string;
html?: string;
text?: string;
replyTo?: string;
tags?: Array<{ name: string; value: string }>;
}
interface SendEmailResponse {
id: string;
}
async function sendEmail(options: SendEmailOptions): Promise<SendEmailResponse> {
const res = await fetch("https://smtpfa.st/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMTPFAST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: options.from,
to: options.to,
subject: options.subject,
html: options.html,
text: options.text,
reply_to: options.replyTo,
tags: options.tags,
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(`SMTPfast error: ${error.message}`);
}
return res.json();
}
Key Takeaways
- No SDK needed - use
fetch()built into Node.js 18+ - Handle rate limits (429) with retry-after headers
- Wrap the API in a reusable module
- Add exponential backoff for production reliability
- Check delivery status via the GET endpoint
Ready to get started?
Start sending transactional email today. Free to start, no credit card required.
Get Started for FreeRelated Posts
One approval instead of five DNS records: Domain Connect on SMTPfast
If your domain is on Cloudflare, SMTPfast can publish its sending records, and separately the inbound MX, through Domain Connect. You review each set on Cloudflare's screen, approve, and the records are written for you. Here is how it works, what gets written, and what to do when your DNS lives elsewhere.
Logs API and webhook deliveries: answer 'did it send?' without opening the dashboard
Two additions for the debugging side of email: the event log behind the Logs page is now an API, and every webhook has a delivery log with attempts, responses, automatic retries and a retry button.