Command-line tool to send an email, or automate repetitive emails.
Built with TypeScript and nodemailer. Engine-like design β can be embedded in VS Code extensions, GUIs, or any Node.js application.
Ctrl + click to view docs
# Install dependencies
npm install
# Build TypeScript
npm run build
# Send a quick text email
sendEmail -t someone@example.com "Hello from sendEmail"
# Show full help
sendEmail -hRun the setup script to create config/accounts/_default.js from the template:
bash .github/scripts/setup.sh.github\scripts\setup.batThen edit config/accounts/_default.js with your credentials.
For Gmail, use an App Password (requires 2FA).
Caution
config/accounts/ is excluded from git β it contains real credentials.
Never run git add -f config/accounts/ β this bypasses .gitignore and will expose your credentials.
See config/README.md for full details.
npm run build# Unix/macOS
chmod +x bin/sendEmail.sh
ln -s $(pwd)/bin/sendEmail.sh /usr/local/bin/sendEmail
# Windows: add the bin/ directory to your PATHsendEmail [options] [arguments]
| Mode | Example |
|---|---|
| Raw (quick text) | sendEmail -t user@example.com "Message" |
| Normal (structured) | sendEmail --send-to user@example.com --subject "Hello" --message-html body.html |
| Repetitive (bulk) | sendEmail --config-email newsletter --email-list subscribers --force |
# Quick text email
sendEmail -t someone@example.com "Quick message"
# HTML email
sendEmail --send-to john@example.com --subject "Report" --message-html ./report.html
# Markdown email (auto-converted to HTML)
sendEmail --send-to team@company.com --subject "Update" --message-file ./update.md
# Configured email template
sendEmail --config-email billing --send-to client@example.com
# Bulk send to list
sendEmail --config-email newsletter --email-list subscribers --force
# Terminal Format Mode β embed live command output in argument values (--command-format first)
sendEmail --command-format \
--send-to dev@example.com \
--subject "$> {{ git log --oneline -1 }};"
# Copy tool to a project (auto-creates config/accounts/_default.js via setup)
sendEmail --copy ./my-project # full tool [null:reproductive <tools>]
sendEmail --copy:config ./my-project # config/support types only [null:reproductive <config>]
# Show help
sendEmail -h
sendEmail -h options
sendEmail -h options:configurableRelative paths for --message-file, --message-html, and --message-text are resolved from your current working directory first; if no match is found, sendEmail falls back to its config/tool root.
sendEmail/
βββ src/
β βββ core/ # Core engine (interface-agnostic)
β β βββ engine.ts # EmailEngine class
β β βββ types.ts # All TypeScript interfaces
β β βββ config-loader.ts # Load configurations
β β βββ template-engine.ts # Template variable substitution
β β βββ list-processor.ts # Email list iteration
β β βββ attachment-loader.ts
β β βββ validator.ts
β βββ cli/ # CLI entry point
β β βββ index.ts # Main CLI runner
β β βββ parser.ts # Argument parsing
β β βββ help.ts # Help documentation
β β βββ prompts.ts # Confirmation prompts
β β βββ terminal-format.ts # --command-format terminal mode processor
β βββ utils/ # Utilities
β β βββ file-utils.ts
β β βββ logger.ts
β β βββ error-handler.ts
β β βββ markdown-html.ts
β βββ tools/ # Tool scripts
β βββ list-generator.ts # --new-list
β βββ copy-tool.ts # --copy
β βββ test-runner.ts # --test
βββ bin/
β βββ sendEmail.js # Node.js entry (npm bin)
β βββ sendEmail.sh # Unix/macOS wrapper
β βββ sendEmail.cmd # Windows CMD wrapper
β βββ sendEmail.ps1 # PowerShell wrapper
βββ config/
β βββ _accounts/ # Template (versioned) β rename to accounts/ to activate
β βββ accounts/ # !! git-ignored !! β your real credentials live here
β β βββ _default.js # REQUIRED default account
β β βββ example.js
β βββ emails/ # Configured email templates
β β βββ billing/
β β βββ example/
β βββ globals/ # Reusable global templates
β βββ footer/ # Global: 'footer'
β β βββ billing/ # Nested global: 'footer/billing'
β βββ example/
βββ lists/ # Email lists (.json)
βββ attachments/ # Email attachments
βββ img/ # Embedded images
βββ tests/
β βββ unit/ # Unit tests (vitest)
β βββ mock/server/ # Mock SMTP server
β βββ logs/ # Test logs
βββ docs/
βββ CONFIGURE.md # Email template and global configuration
βββ CLI-OPTIONS.md # Full options reference
βββ CLI-CHEATSHEET.md # Quick reference
βββ API.md # Engine API documentation
βββ EXAMPLES.md # Real-world examples
βββ TEMPLATING.md # Template variables and global tags
βββ TERMINAL-FORMAT.md # Terminal Mode (--command-format)
βββ TYPES.md # Type reference
// New-style (recommended):
export const account = {
service: 'gmail',
auth: { user: 'your@gmail.com', pass: 'app-password' },
};
// Or with custom SMTP:
export const account = {
host: 'smtp.example.com',
port: 587,
secure: false,
auth: { user: 'user@example.com', pass: 'password' },
};{
"from": "_default",
"subject": "Billing Statement - {{contact.name}}",
"html": "billingStatement",
"globals": ["footer"]
}{
"email-list": [
{ "email": "alice@example.com", "name": "Alice" },
{ "email": "bob@example.com", "name": "Bob" }
]
}Use in subject lines, HTML templates, configurable text, and attachment filenames/paths:
| Variable | Value |
|---|---|
{{contact.name}} |
Contact's name |
{{contact.email}} |
Contact's email |
{{contact.<field>}} |
Any custom field |
{{date}} |
2026-02-19 |
{{date.formatted}} |
February 19, 2026 |
{{list.index}} |
Current index (bulk send) |
{{list.count}} |
Total recipients |
Extended date formatting powered by @jhauga/getdate:
| Variable | Value |
|---|---|
{{dates.lastMonth}} |
Previous month name (January) |
{{dates.month}} |
Current month name (February) |
{{dates.quarter}} |
Current fiscal quarter (1) |
{{dates.lastQuarter}} |
Previous fiscal quarter (4) |
{{dates.year}} |
Four-digit year (2026) |
{{dates.lastYear}} |
Previous year (2025) |
{{dates.nextYear}} |
Next year (2027) |
{{dates.fullDate}} |
Full date MM-DD-YYYY (02-26-2026) |
{{dates.isoDate}} |
ISO date YYYY-MM-DD (2026-02-26) |
Example β monthly report subject:
{
"subject": "{{dates.lastMonth}} {{dates.year}} - Revenue Summary"
}Result: "January 2026 - Revenue Summary" (when sent in February)
Example β dynamic attachment filenames:
export const emailAttachments = [
{
filename: 'Report - {{dates.lastMonth}} {{dates.year}}.pdf',
path: 'attachments/{{dates.year}}/report.pdf',
},
];For complex date logic, use function exports in email.js:
export const emailAttachments = (dates) => {
const theYear = dates.lastMonth === "January" ? dates.lastYear : dates.year;
return [{
filename: `Report - ${dates.lastMonth} ${theYear}.pdf`,
path: `reports/${theYear}/report.pdf`,
}];
};Define custom template variables in email.js that can be used in the sibling email.json:
// config/emails/billing/email.js
var theYear;
var date = new Date();
if (date.getMonth() === 0) {
theYear = '{{dates.lastYear}}'; // January: use previous year
} else {
theYear = '{{dates.year}}';
}
export const emailVars = {
theYear,
reportType: 'Monthly'
};// config/emails/billing/email.json
{
"subject": "{{reportType}} Report - {{dates.lastMonth}} {{theYear}}",
"to": "reports@example.com"
}See TEMPLATING.md for full variable reference.
Legacy placeholders (CH-EMAILONLIST, CHANGE_SEND_TO) are also supported.
Reusable HTML/text snippets and attachments, stored in config/globals/<name>/.
Embed a global template inside any email HTML or text file:
{% global 'footer' %}When buildMessage() processes the template, the tag is replaced with the global's HTML (or text) content, and the global's attachments (from global.js) are automatically merged into the email.
Global folders can contain nested sub-globals:
config/globals/
footer/
billing/
global.js β 'footer/billing'
html.htm β optional HTML data
global.js β 'footer'
html.htm β optional HTML data
Reference a nested global:
{% global 'footer/billing' %}| File | Description |
|---|---|
global.js |
Required β declares globalAttachments array |
html.htm or html.html |
Optional β HTML content (root, strict naming) |
text.txt |
Optional β text content (root, strict naming) |
html/<anyFile> |
Optional β HTML content (subfolder, relaxed naming) |
data/<anyFile> |
Optional β text content (subfolder, relaxed naming) |
See docs/TEMPLATING.md for the full templating reference.
import { EmailEngine, createEngineConfig } from './dist/core/engine.js';
const engine = new EmailEngine(createEngineConfig(process.cwd()));
await engine.initialize();
const result = await engine.sendEmail({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Hello',
html: '<p>Hello, World!</p>',
});See docs/API.md for full API documentation.
| Command | Description |
|---|---|
npm run build |
Compile TypeScript to dist/ |
npm run build:watch |
Watch mode compilation |
npm run dev |
Run CLI directly with tsx (no build needed) |
npm test |
Run tests in watch mode |
npm run test:run |
Run all tests once |
sendEmail --test |
Run tests via CLI |
-
CONFIGURE.md β How to configure email templates in
config/emails/and global elements inconfig/globals/. Covers allemail.jsonproperties,email.jsattachment definitions, HTML and text file layout, and complete examples including multiple recipients, date helper syntax, inline lists, and DSN. -
CLI-OPTIONS.md β Complete reference for every command-line option. Documents configurable options (usable in both CLI and
email.json), non-configurable options, and tool options, including full syntax for--config-email,--email-list,--global-config, and the attachment flags. -
CLI-CHEATSHEET.md β Quick-reference card for the most common
sendEmailpatterns. Covers raw mode, normal mode, bulk send, and the most frequently used flags in a compact format. -
API.md β Engine API documentation for embedding
EmailEnginein TypeScript/JavaScript projects. Covers theEmailEngineclass, all public methods, configuration interfaces, and examples for library usage. -
EXAMPLES.md β Over 20 annotated real-world examples covering every send mode. Includes bulk send workflows, inline image attachments, template variable usage, terminal format mode, and account configuration patterns.
-
TEMPLATING.md β Full reference for template variables, the
{% global %}tag, and global folder structure. Explains resolution rules, content preference (HTML vs text), nested globals, and the config type classification system. -
TERMINAL-FORMAT.md β Reference for Terminal Mode (
--command-format), which lets you embed live shell command output in CLI argument values. Documents the$>command: {{ }};syntax, prohibited commands, and interaction with template variables. -
TYPES.md β Full type reference for
OptionType,ConfigItemType, and send mode classifications. Useful for understanding how options and config files are categorized internally and for contributors extending the tool.