Build a CLI Email Sender with Node.js + MailAnvil
Sending emails from a terminal script is a common need for DevOps engineers, sysadmins, and backend developers. Whether you want deployment alerts, cron job failure notifications, or a quick way to test your email templates, a CLI tool saves time.
In this tutorial, you'll build a lightweight CLI email sender using Node.js and the MailAnvil API. The tool supports plain text and HTML, works in bash scripts, and takes about 20 lines of code.
Prerequisites
- Node.js 18+ installed
- A MailAnvil account (free tier: 500 emails/month at mailanvil.com)
- An API key from the MailAnvil dashboard
- A verified sending domain in MailAnvil
Project Setup
Create a new directory and initialize:
mkdir mailanvil-cli && cd mailanvil-cli
npm init -y
No external dependencies needed — we'll use Node's built-in fetch (available since Node 18).
The CLI Script
Create send-email.js:
#!/usr/bin/env node
const API_BASE = 'https://api.mailanvil.com/v1';
const API_KEY = process.env.MAILANVIL_API_KEY;
async function sendEmail({ to, subject, text, html }) {
if (!API_KEY) {
console.error('Error: MAILANVIL_API_KEY environment variable not set.');
process.exit(1);
}
const body = {
from: process.env.MAILANVIL_FROM || '[email protected]',
to: [to],
subject,
text,
html: html || text,
};
const res = await fetch(`${API_BASE}/send`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) {
console.error(`Failed: ${data.error?.message || res.statusText}`);
process.exit(1);
}
console.log(`Email queued. ID: ${data.id}`);
}
// Parse CLI arguments
const args = process.argv.slice(2);
const flags = {};
for (let i = 0; i < args.length; i += 2) {
flags[args[i].replace(/^--/, '')] = args[i + 1];
}
if (!flags.to || !flags.subject) {
console.log('Usage: node send-email.js --to [email protected] --subject "Subject" --text "Body"');
console.log('Optional: --html "<h1>HTML body</h1>" --from "[email protected]"');
process.exit(0);
}
sendEmail(flags);
Make it executable:
chmod +x send-email.js
Usage
Set your API key as an environment variable:
export MAILANVIL_API_KEY="your-api-key-here"
export MAILANVIL_FROM="[email protected]"
Send a plain text email:
node send-email.js \
--to [email protected] \
--subject "Deployment complete" \
--text "v2.1.0 deployed to production at $(date)"
Send an HTML email:
node send-email.js \
--to [email protected] \
--subject "Invoice #1234" \
--text "Your invoice is attached." \
--html "<h1>Invoice #1234</h1><p>Total: Rp 149,000</p>"
Using in Bash Scripts
The real power is calling it from other scripts. Add it to a deployment script:
#!/bin/bash
set -e
# Deploy
echo "Deploying..."
./deploy.sh
# Notify team
node ~/mailanvil-cli/send-email.js \
--to [email protected] \
--subject "Deploy: $(git log --oneline -1)" \
--text "Deployment succeeded at $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--from "[email protected]"
echo "Done."
Or use it in a cron job for failure alerts:
# In crontab — send alert if backup fails
0 3 * * * /usr/local/bin/backup.sh || \
node /path/to/send-email.js \
--to [email protected] \
--subject "BACKUP FAILED" \
--text "Nightly backup failed at $(date)" \
--from "[email protected]"
Advanced: Read Body from File
For longer emails, pipe from a file:
// Add to send-email.js before sendEmail() call
if (flags.bodyFile) {
const fs = await import('fs');
flags.text = fs.readFileSync(flags.bodyFile, 'utf8');
}
Usage:
node send-email.js \
--to [email protected] \
--subject "Weekly report" \
--body-file /tmp/report.txt
Error Handling
The MailAnvil API returns structured errors:
{
"error": {
"code": "UNVERIFIED_DOMAIN",
"message": "Sending domain not verified"
}
}
Common errors to handle:
| Code | Meaning | Fix |
|---|---|---|
UNVERIFIED_DOMAIN |
Domain DKIM not verified | Verify in dashboard |
SUPPRESSED |
Recipient is suppressed | Check suppression list |
RATE_LIMITED |
Too many requests | Back off, check rate limits |
UNAUTHORIZED |
Bad API key | Check MAILANVIL_API_KEY |
Why MailAnvil for CLI Tools
For Indonesian developers, MailAnvil has a few advantages for scripting:
- IDR pricing — Rp 0 free tier, Rp 149,000/month starter. No USD conversion surprises.
- Edge delivery — API runs on Cloudflare Workers, so low latency from Indonesia.
- Simple API — One POST endpoint for sending. No SDK needed for a CLI tool.
- QRIS/GoPay — Pay with local payment methods when you outgrow the free tier.
Try MailAnvil free at mailanvil.com