Prerequisites
To get the most out of this guide, you’ll need to:- Create a SendPost Account
- Node.js 14+ and Express.js
- A Sub-Account API Key from your SendPost dashboard
You can find your API keys in your SendPost Dashboard. Make sure to use your Sub-Account API Key for sending emails.
1. Install Dependencies
npm
npm install express sendpost-js-sdk dotenv
2. Environment Setup
Create a.env file in your project root:
SENDPOST_API_KEY=your_sub_account_api_key
SENDPOST_FROM_EMAIL=hello@playwithsendpost.io
SENDPOST_FROM_NAME=SendPost
PORT=3000
3. Basic Setup
Createapp.js or server.js:
JavaScript
require('dotenv').config();
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
4. Create Email Service
Createservices/emailService.js:
JavaScript
const sendpost = require('sendpost-js-sdk');
const emailApi = new sendpost.EmailApi();
class EmailService {
constructor() {
this.apiKey = process.env.SENDPOST_API_KEY;
this.fromEmail = process.env.SENDPOST_FROM_EMAIL;
this.fromName = process.env.SENDPOST_FROM_NAME;
}
async sendEmail({
to,
subject,
htmlBody,
textBody,
from,
groups,
trackOpens = true,
trackClicks = true,
customFields,
}) {
try {
const emailMessage = new sendpost.EmailMessage();
emailMessage.from = from || {
email: this.fromEmail,
name: this.fromName,
};
// Handle single email string or array of recipients
if (typeof to === 'string') {
emailMessage.to = [{ email: to }];
} else {
emailMessage.to = to.map(recipient => {
if (typeof recipient === 'string') {
return { email: recipient };
}
return recipient;
});
}
emailMessage.subject = subject;
emailMessage.htmlBody = htmlBody;
emailMessage.textBody = textBody || htmlBody.replace(/<[^>]*>/g, '');
emailMessage.trackOpens = trackOpens;
emailMessage.trackClicks = trackClicks;
if (groups) {
emailMessage.groups = Array.isArray(groups) ? groups : [groups];
}
const opts = { emailMessage };
const response = await emailApi.sendEmail(this.apiKey, opts);
return {
success: true,
messageId: response.messageId,
data: response,
};
} catch (error) {
console.error('SendPost error:', error);
return {
success: false,
error: error.message || 'Failed to send email',
details: error,
};
}
}
}
module.exports = new EmailService();
5. Send Your First Email
Simple Route Handler
JavaScript
const emailService = require('./services/emailService');
app.post('/api/send-email', async (req, res) => {
try {
const { to, subject, htmlBody, textBody } = req.body;
if (!to || !subject || !htmlBody) {
return res.status(400).json({
success: false,
error: 'Missing required fields: to, subject, htmlBody',
});
}
const result = await emailService.sendEmail({
to,
subject,
htmlBody,
textBody,
});
if (result.success) {
res.json({
success: true,
messageId: result.messageId,
});
} else {
res.status(500).json({
success: false,
error: result.error,
});
}
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
6. Common Use Cases
Welcome Email Route
JavaScript
app.post('/api/welcome-email', async (req, res) => {
try {
const { email, firstName } = req.body;
const result = await emailService.sendEmail({
to: {
email,
name: firstName,
customFields: { firstName },
},
subject: 'Welcome {{firstName}}!',
htmlBody: `
<h1>Welcome, {{firstName}}!</h1>
<p>Thank you for joining us. We're excited to have you on board.</p>
<p>Get started by exploring our features:</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
<p>If you have any questions, just reply to this email.</p>
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
`,
textBody: `
Welcome, {{firstName}}!
Thank you for joining us. We're excited to have you on board.
Get started by exploring our features:
- Feature 1
- Feature 2
- Feature 3
If you have any questions, just reply to this email.
Unsubscribe: {{unsubscribe}}
`,
groups: ['welcome'],
});
if (result.success) {
res.json({ success: true, messageId: result.messageId });
} else {
res.status(500).json({ success: false, error: result.error });
}
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
Password Reset Email
JavaScript
app.post('/api/password-reset', async (req, res) => {
try {
const { email, resetToken, firstName } = req.body;
const resetUrl = `${process.env.APP_URL}/reset-password?token=${resetToken}`;
const result = await emailService.sendEmail({
to: {
email,
name: firstName,
customFields: {
firstName,
resetUrl,
},
},
subject: 'Reset Your Password',
htmlBody: `
<h2>Hello {{firstName}},</h2>
<p>We received a request to reset your password. Click the button below to create a new password:</p>
<p>
<a href="{{resetUrl}}" style="background-color: #5750EC; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
Reset Password
</a>
</p>
<p>Or copy and paste this link into your browser:</p>
<p>{{resetUrl}}</p>
<p>This link will expire in 1 hour.</p>
<p>If you didn't request this, please ignore this email.</p>
`,
textBody: `
Hello {{firstName}},
We received a request to reset your password. Click the link below:
{{resetUrl}}
This link will expire in 1 hour.
If you didn't request this, please ignore this email.
`,
groups: ['password-reset'],
trackClicks: true,
});
if (result.success) {
res.json({ success: true, messageId: result.messageId });
} else {
res.status(500).json({ success: false, error: result.error });
}
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
Order Confirmation Email
JavaScript
app.post('/api/order-confirmation', async (req, res) => {
try {
const { email, firstName, orderId, items, total } = req.body;
const result = await emailService.sendEmail({
to: {
email,
name: firstName,
customFields: {
firstName,
orderId,
items,
total: total.toFixed(2),
},
},
subject: 'Order {{orderId}} Confirmed',
htmlBody: `
<h1>Thank you for your order, {{firstName}}!</h1>
<p>Your order <strong>{{orderId}}</strong> has been confirmed.</p>
<h2>Order Details</h2>
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background-color: #f5f5f5;">
<th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Item</th>
<th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Quantity</th>
<th style="padding: 12px; text-align: right; border: 1px solid #ddd;">Price</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td style="padding: 12px; border: 1px solid #ddd;">{{name}}</td>
<td style="padding: 12px; border: 1px solid #ddd;">{{quantity}}</td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;">${{price}}</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="2" style="padding: 12px; text-align: right; border: 1px solid #ddd;"><strong>Total:</strong></td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;"><strong>${{total}}</strong></td>
</tr>
</tfoot>
</table>
<p>We'll send you a shipping confirmation once your order is on its way.</p>
<p><a href="{{unsubscribe}}">Unsubscribe from order updates</a></p>
`,
groups: ['order-confirmation'],
});
if (result.success) {
res.json({ success: true, messageId: result.messageId });
} else {
res.status(500).json({ success: false, error: result.error });
}
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
7. Using Middleware for Email Routes
Createmiddleware/emailValidation.js:
JavaScript
const validateEmailRequest = (req, res, next) => {
const { to, subject, htmlBody } = req.body;
if (!to) {
return res.status(400).json({
success: false,
error: 'Recipient email (to) is required',
});
}
if (!subject) {
return res.status(400).json({
success: false,
error: 'Email subject is required',
});
}
if (!htmlBody) {
return res.status(400).json({
success: false,
error: 'Email HTML body is required',
});
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emails = Array.isArray(to) ? to : [to];
for (const email of emails) {
const emailAddress = typeof email === 'string' ? email : email.email;
if (!emailRegex.test(emailAddress)) {
return res.status(400).json({
success: false,
error: `Invalid email format: ${emailAddress}`,
});
}
}
next();
};
module.exports = { validateEmailRequest };
JavaScript
const { validateEmailRequest } = require('./middleware/emailValidation');
app.post('/api/send-email', validateEmailRequest, async (req, res) => {
// ... email sending logic
});
8. Error Handling Middleware
JavaScript
const errorHandler = (err, req, res, next) => {
console.error('Error:', err);
if (err.name === 'ValidationError') {
return res.status(400).json({
success: false,
error: err.message,
});
}
res.status(500).json({
success: false,
error: 'Internal server error',
message: process.env.NODE_ENV === 'development' ? err.message : undefined,
});
};
app.use(errorHandler);
9. Batch Email Sending
JavaScript
app.post('/api/send-batch', async (req, res) => {
try {
const { recipients, subject, htmlBody, textBody } = req.body;
if (!recipients || !Array.isArray(recipients) || recipients.length === 0) {
return res.status(400).json({
success: false,
error: 'Recipients array is required',
});
}
// SendPost supports up to 500 recipients per request
if (recipients.length > 500) {
return res.status(400).json({
success: false,
error: 'Maximum 500 recipients per request',
});
}
const result = await emailService.sendEmail({
to: recipients,
subject,
htmlBody,
textBody,
});
if (result.success) {
res.json({
success: true,
messageId: result.messageId,
recipientsCount: recipients.length,
});
} else {
res.status(500).json({
success: false,
error: result.error,
});
}
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
Make sure your sender email domain is verified in your SendPost account before sending emails.
10. Next Steps
Explore more examples and use cases:Express.js Documentation
Learn more about Express.js framework
SendPost JavaScript SDK
View the official SDK package on npm
Quickstart Example
View a complete working example on GitHub