Skip to main content

Mailer

Balda provides a flexible mailer system with support for multiple email providers and template engines.

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.