Skip to main content

Basic Usage

Learn the three ways to send emails with NestJS Mailable, from simple to advanced.

Method 1: Direct Content

Send emails directly with content objects. Perfect for simple emails.

import { Injectable } from '@nestjs/common';
import { MailService } from 'nestjs-mailable';

@Injectable()
export class EmailService {
constructor(private mailService: MailService) {}

// Simple HTML email
async sendSimple() {
await this.mailService.send({
to: 'user@example.com',
subject: 'Hello World',
html: '<h1>Hello!</h1><p>This is a test email.</p>'
});
}

// Email with multiple recipients
async sendToMany() {
await this.mailService.send({
to: ['user1@example.com', 'user2@example.com'],
cc: 'manager@example.com',
bcc: 'admin@example.com',
subject: 'Team Update',
html: '<p>Here is the team update...</p>'
});
}

// Email with template
async sendWithTemplate() {
await this.mailService.send({
to: 'user@example.com',
subject: 'Welcome!',
template: 'welcome',
context: {
name: 'John Doe',
appName: 'My App'
}
});
}
}

Content Options

interface Content {
// Recipients
to?: string | Address | Array<string | Address>;
cc?: string | Address | Array<string | Address>;
bcc?: string | Address | Array<string | Address>;

// Sender (optional, uses global config if not set)
from?: Address;
replyTo?: Address;

// Content
subject?: string;
html?: string;
text?: string;
template?: string;
context?: Record<string, any>;

// Attachments
attachments?: Attachment[];

// Metadata
headers?: Record<string, string>;
tags?: string[];
metadata?: Record<string, any>;
}

Method 2: Fluent API

Chain methods to build emails step by step. Great for dynamic emails.

@Injectable()
export class EmailService {
constructor(private mailService: MailService) {}

// Basic fluent email
async sendFluent() {
await this.mailService
.to('user@example.com')
.send({
subject: 'Hello',
html: '<p>Hello World!</p>'
});
}

// Complex fluent email
async sendComplexFluent(user: any, manager: any) {
await this.mailService
.to({ address: user.email, name: user.name })
.cc(manager.email)
.bcc('audit@company.com')
.send({
subject: `Welcome ${user.name}!`,
template: 'onboarding',
context: {
user: user,
manager: manager,
startDate: new Date()
}
});
}

// Send to multiple people individually
async sendToMultiple(users: any[]) {
for (const user of users) {
await this.mailService
.to(user.email)
.send({
subject: `Personal message for ${user.name}`,
template: 'personal',
context: { user }
});
}
}
}

Available Chain Methods

// Set recipients
.to(address) // Main recipient(s)
.cc(address) // Carbon copy
.bcc(address) // Blind carbon copy

// Send the email
.send(content) // Send with content or Mailable

Address Formats

// String
.to('user@example.com')

// Address object
.to({ address: 'user@example.com', name: 'John Doe' })

// Array of strings
.to(['user1@example.com', 'user2@example.com'])

// Array of Address objects
.to([
{ address: 'user1@example.com', name: 'User One' },
{ address: 'user2@example.com', name: 'User Two' }
])

Method 3: Mailable Classes

Create reusable email classes. Perfect for complex emails used in multiple places.

Legacy Mailable (Simple)

import { Mailable } from 'nestjs-mailable';

export class WelcomeEmail extends Mailable {
constructor(
private user: { name: string; email: string },
private company: string
) {
super();
}

build() {
return this
.subject(`Welcome to ${this.company}, ${this.user.name}!`)
.view('emails/welcome', {
userName: this.user.name,
companyName: this.company
})
.tag('welcome')
.tag('onboarding')
.metadata('userId', this.user.email);
}
}

// Usage
@Injectable()
export class UserService {
constructor(private mailService: MailService) {}

async welcomeNewUser(user: any) {
const welcomeEmail = new WelcomeEmail(user, 'Acme Corp');
await this.mailService.send(welcomeEmail);
}
}

Advanced Mailable

import { 
Mailable,
MailableEnvelope,
MailableContent,
MailableAttachment,
AttachmentBuilder
} from 'nestjs-mailable';

export class OrderConfirmation extends Mailable {
constructor(private order: any) {
super();
}

envelope(): MailableEnvelope {
return {
subject: `Order Confirmation #${this.order.id}`,
tags: ['order', 'confirmation'],
metadata: {
orderId: this.order.id,
customerId: this.order.customerId
}
};
}

content(): MailableContent {
return {
template: 'emails/order-confirmation',
with: {
order: this.order,
customer: this.order.customer,
total: this.order.total
}
};
}

attachments(): MailableAttachment[] {
return [
AttachmentBuilder
.fromPath('./receipts/receipt.pdf')
.as(`receipt-${this.order.id}.pdf`)
.build()
];
}
}

// Usage
await this.mailService
.to(order.customer.email)
.send(new OrderConfirmation(order));

Attachments

Direct Content Attachments

await this.mailService.send({
to: 'user@example.com',
subject: 'Files attached',
html: '<p>Please find files attached.</p>',
attachments: [
{
filename: 'report.pdf',
path: './files/report.pdf'
},
{
filename: 'data.csv',
content: Buffer.from('name,email\nJohn,john@example.com'),
contentType: 'text/csv'
}
]
});

Legacy Mailable Attachments

export class ReportEmail extends Mailable {
constructor(private reportData: string) {
super();
}

build() {
return this
.subject('Monthly Report')
.view('reports/monthly')
.attach('./reports/monthly.pdf')
.attachData(Buffer.from(this.reportData), 'data.csv', {
contentType: 'text/csv'
});
}
}

Advanced Mailable Attachments

export class InvoiceEmail extends Mailable {
constructor(private invoice: any) {
super();
}

attachments(): MailableAttachment[] {
return [
// File attachment
AttachmentBuilder
.fromPath(`./invoices/${this.invoice.id}.pdf`)
.as(`invoice-${this.invoice.number}.pdf`)
.withMime('application/pdf')
.build(),

// Data attachment
AttachmentBuilder
.fromData(() => this.generateCsvData(), 'details.csv')
.withMime('text/csv')
.build(),

// Storage attachment
AttachmentBuilder
.fromStorage(`logos/company-logo.png`)
.as('logo.png')
.build()
];
}

private generateCsvData(): string {
return 'item,price\nService,100.00';
}
}

Headers and Metadata

Custom Headers

await this.mailService.send({
to: 'user@example.com',
subject: 'Custom Headers',
html: '<p>Email with custom headers</p>',
headers: {
'X-Priority': '1',
'X-Mailer': 'My App'
}
});

Tags (for tracking)

await this.mailService.send({
to: 'user@example.com',
subject: 'Newsletter',
html: '<p>Monthly newsletter</p>',
tags: ['newsletter', 'monthly', 'marketing']
});

Metadata (for analytics)

await this.mailService.send({
to: 'user@example.com',
subject: 'Welcome',
html: '<p>Welcome!</p>',
metadata: {
userId: '123',
campaign: 'welcome-series',
version: 'A'
}
});

Error Handling

@Injectable()
export class EmailService {
constructor(private mailService: MailService) {}

async sendWithErrorHandling() {
try {
await this.mailService.send({
to: 'user@example.com',
subject: 'Test',
html: '<p>Test message</p>'
});
console.log('Email sent successfully');
} catch (error) {
console.error('Failed to send email:', error.message);
// Handle error - retry, log, notify admin, etc.
}
}

async sendBulkWithErrorHandling(users: any[]) {
const results = [];

for (const user of users) {
try {
await this.mailService.to(user.email).send({
subject: 'Bulk Email',
template: 'bulk',
context: { user }
});
results.push({ user: user.email, status: 'sent' });
} catch (error) {
results.push({ user: user.email, status: 'failed', error: error.message });
}
}

return results;
}
}

Best Practices

1. Use Templates for Reusable Content

// Good: Use templates
await this.mailService.send({
template: 'welcome',
context: { name: user.name }
});

// Avoid: Hardcoded HTML
await this.mailService.send({
html: '<h1>Welcome John!</h1>' // Hard to maintain
});

2. Use Mailable Classes for Complex Emails

// Good: Organized in classes
export class OrderConfirmation extends Mailable {
// Logic here
}

// Avoid: Complex inline content
await this.mailService.send({
/* lots of complex content here */
});

3. Handle Errors Gracefully

// Good: Handle errors
try {
await this.mailService.send(email);
} catch (error) {
this.logger.error('Email failed', error);
}

// Avoid: Unhandled errors
await this.mailService.send(email); // Might crash app

4. Use Tags for Analytics

// Good: Trackable emails
await this.mailService.send({
// ... content
tags: ['newsletter', 'december-2023']
});

This covers all the basic usage patterns. Next, check out Mailable Classes for more advanced patterns and Templates for template engine usage.