Mailer
Balda provides a flexible mailer system with support for multiple email providers and template engines. Install nodemailer plus one template engine of your choice (e.g. pnpm add nodemailer handlebars). The mailer is self‑contained and does not depend on the queue feature.
Quick Setup with CLI
The fastest way to get started is using the init-mailer command:
# Initialize with Handlebars template engine
npx balda init-mailer -t handlebars
# Initialize without a template engine
npx balda init-mailer -t none
# Initialize with custom output directory
npx balda init-mailer -t ejs -o src/email
This command will:
- Install all required dependencies
- Create a ready-to-use mailer configuration file
- Set up your chosen template engine
- Include environment variable templates
- Provide usage examples
See the init-mailer command documentation for more details.
Manual Installation
If you prefer manual setup, install Nodemailer (required):
npm install nodemailer
npm install --save-dev @types/nodemailer
Install template engines (optional, only what you need):
# Handlebars
npm install handlebars
npm install --save-dev @types/handlebars
# Edge.js
npm install edge.js
# Mustache
npm install mustache
npm install --save-dev @types/mustache
# EJS
npm install ejs
npm install --save-dev @types/ejs
Quick Start
import { Mailer, HandlebarsAdapter } from "balda";
import nodemailer from "nodemailer";
const mailer = new Mailer(
{
smtp: {
transporter: nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
}),
templateAdapter: new HandlebarsAdapter(),
from: "noreply@example.com",
},
},
{ defaultProvider: "smtp" },
);
// Send email using builder callback
await mailer.send((builder) =>
builder
.to("user@example.com")
.subject("Welcome!")
.html("<h1>Hello World</h1>"),
);
Sending Emails
Send Immediately
await mailer.send((builder) =>
builder
.to("user@example.com")
.subject("Welcome!")
.html("<h1>Hello</h1>")
.attachment({ filename: "invoice.pdf", content: pdfBuffer }),
);
Queue for Later
Queue emails for background processing with 1-second delays between sends. Useful for bulk sending, rate limiting, and reducing server load.
await mailer.later((builder) =>
builder.to("user@example.com").subject("Newsletter").html("<h1>Update</h1>"),
);
Templates
Inline Template
await mailer.send((builder) =>
builder
.to("user@example.com")
.subject("Order #{{orderId}}")
.template("<h1>Order #{{orderId}}</h1><p>Total: ${{total}}</p>", {
orderId: "12345",
total: 99.99,
}),
);
Template File
await mailer.send((builder) =>
builder
.to("user@example.com")
.subject("Welcome")
.templateFile("./templates/welcome.hbs", {
name: "John",
verificationUrl: "https://example.com/verify",
}),
);
Supported Template Engines
Configure with your preferred adapter:
import {
HandlebarsAdapter,
EdgeAdapter,
MustacheAdapter,
EjsAdapter,
CustomAdapter,
} from "balda";
// In mailer config
templateAdapter: new HandlebarsAdapter(), // or EdgeAdapter, etc.
Custom Adapter allows registering custom helpers:
const adapter = new CustomAdapter();
adapter.registerHelper("uppercase", (value) => String(value).toUpperCase());
Multiple Providers
const mailer = new Mailer(
{
smtp: {
transporter: nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
auth: { user: "user", pass: "pass" },
}),
from: "noreply@example.com",
},
sendgrid: {
transporter: nodemailer.createTransport({
host: "smtp.sendgrid.net",
port: 587,
auth: { user: "apikey", pass: process.env.SENDGRID_API_KEY },
}),
from: "marketing@example.com",
},
},
{ defaultProvider: "smtp" },
);
// Use default provider
await mailer.send((builder) =>
builder.to("user@example.com").subject("Test").text("Hello"),
);
// Switch provider
await mailer
.use("sendgrid")
.send((builder) =>
builder.to("user@example.com").subject("Newsletter").html("<h1>News</h1>"),
);
Attachments
await mailer.send((builder) =>
builder
.to("user@example.com")
.subject("Invoice")
.html("<p>See attached</p>")
.attachment({ filename: "invoice.pdf", content: pdfBuffer })
.attachments([
{ filename: "file1.pdf", content: buffer1 },
{ filename: "file2.pdf", path: "/path/to/file2.pdf" },
]),
);
API Reference
Builder Methods
builder
.from(email: string)
.to(email: string | string[]) // required
.cc(email: string | string[])
.bcc(email: string | string[])
.subject(text: string) // required
.text(content: string)
.html(content: string)
.template(template: string, data: object)
.templateFile(path: string, data: object)
.attachment(attachment: Attachment)
.attachments(attachments: Attachment[]);
Mailer Methods
await mailer.send(builderFn); // Send immediately
await mailer.later(builderFn); // Queue for background processing
await mailer.verify(); // Verify connection
mailer.use(provider); // Switch provider
Testing with MailCatcher
For local development, use MailCatcher:
# docker-compose.yml
mailcatcher:
image: schickling/mailcatcher
ports:
- "1025:1025" # SMTP
- "1080:1080" # Web UI
const mailer = new Mailer(
{
mailcatcher: {
transporter: nodemailer.createTransport({
host: "localhost",
port: 1025,
ignoreTLS: true,
}),
from: "test@example.com",
},
},
{ defaultProvider: "mailcatcher" },
);
Visit http://localhost:1080 to view sent emails.