@zola_do/email
v0.2.9
Published
Email service for NestJS
Downloads
837
Maintainers
Readme
@zola_do/email
Email service for NestJS applications with SMTP transport and Handlebars template support.
Overview
@zola_do/email provides:
- SMTP Transport — Configurable via environment variables
- Handlebars Templates — Server-side template rendering
- HTML Emails — Send rich HTML content
- Connection Verification — Test SMTP connection
- NestJS Integration — Module-based setup
Installation
# Install individually
npm install @zola_do/email
# Or via meta package
npm install @zola_do/nestjs-sharedDependencies
npm install @nestjs-modules/mailer nodemailer
npm install @types/nodemailer --save-devQuick Start
1. Configure Environment
# .env
EMAIL_SMTP=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USERNAME=your-username
EMAIL_SMTP_PASSWORD=your-password
EMAIL_SMTP_DISPLAY_NAME=My App <[email protected]>2. Register Module
import { Module } from '@nestjs/common';
import { EmailModule } from '@zola_do/email';
@Module({
imports: [EmailModule],
})
export class AppModule {}3. Send Emails
import { Injectable } from '@nestjs/common';
import { EmailService } from '@zola_do/email';
@Injectable()
export class NotificationService {
constructor(private readonly emailService: EmailService) {}
async sendWelcomeEmail(userEmail: string, userName: string) {
await this.emailService.sendEmail({
to: userEmail,
subject: 'Welcome to Our App',
html: `
<h1>Welcome, ${userName}!</h1>
<p>Thanks for signing up.</p>
`,
});
}
}Email Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ Email Flow │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Controller/Service │
│ │ │
│ │ 1. Prepare email data │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ EmailService │ │
│ │ │ │
│ │ sendEmail({ to, subject, html }) │ │
│ └──────────────────┬──────────────────┘ │
│ │ │
│ │ 2. Render template (optional) │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ templates/ │ │
│ │ welcome.hbs │ │
│ └──────────────────┬──────────────────┘ │
│ │ │
│ │ 3. Send via SMTP │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ nodemailer │ │
│ │ (SMTP Transport) │ │
│ └──────────────────┬──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ SMTP │ │
│ │ Server │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘EmailService
Send HTML Email
async sendEmail(options: {
to: string | string[];
subject: string;
html: string;
from?: string;
replyTo?: string;
cc?: string | string[];
bcc?: string | string[];
attachments?: Attachment[];
}): Promise<SentMessageInfo>Send with Template
import { MailerService } from '@nestjs-modules/mailer';
import { context } from '@handlebars/noder';
@Injectable()
export class NotificationService {
constructor(
private readonly emailService: EmailService,
private readonly mailerService: MailerService,
) {}
async sendWelcomeWithTemplate(user: User) {
await this.mailerService.sendMail({
to: user.email,
subject: 'Welcome!',
template: 'welcome', // Looks for templates/welcome.hbs
context: {
name: user.name,
verifyUrl: `https://example.com/verify/${user.token}`,
},
});
}
}Verify Connection
async testConnection() {
const isConnected = await this.emailService.verify();
if (!isConnected) {
throw new Error('Email service not available');
}
}Handlebars Templates
Template Location
Templates should be placed in process.cwd() + '/templates/':
project/
├── templates/
│ ├── welcome.hbs
│ ├── reset-password.hbs
│ └── invoice.hbs
├── src/
│ └── app.module.ts
└── package.jsonTemplate Example
{{! templates/welcome.hbs }}
<html>
<head>
<meta charset='utf-8' />
<title>Welcome</title>
<style>
body {
font-family: Arial, sans-serif;
}
.container {
max-width: 600px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class='container'>
<h1>Welcome, {{name}}!</h1>
<p>Thank you for joining {{appName}}.</p>
<a href='{{verifyUrl}}'>Verify your email</a>
<p>Best,<br />The Team</p>
</div>
</body>
</html>Template Features
{{! Conditionals }}
{{#if user.isPremium}}
<p>You have premium access!</p>
{{else}}
<p>Upgrade to premium for more features.</p>
{{/if}}
{{! Loops }}
{{#each items}}
<li>{{ this.name }} - {{ this.price }}</li>
{{/each}}
{{! Partials }}
{{> header }}
{{> footer }}
{{! Helpers }}
{{formatDate date 'MMMM Do YYYY'}}
{{currency amount}}
{{uppercase name}}EmailConfig
Default Configuration
{
transport: {
host: process.env.EMAIL_SMTP,
port: parseInt(process.env.EMAIL_SMTP_PORT, 10),
secure: false, // true for 465, false for other ports
auth: {
user: process.env.EMAIL_SMTP_USERNAME,
pass: process.env.EMAIL_SMTP_PASSWORD,
},
},
defaults: {
from: process.env.EMAIL_SMTP_DISPLAY_NAME || '[email protected]',
},
template: {
dir: process.cwd() + '/templates/',
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
}Custom Configuration
import { Module } from '@nestjs/common';
import { EmailModule, EmailConfig } from '@zola_do/email';
@Module({
imports: [
EmailModule.forRoot({
transport: {
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: '[email protected]',
pass: 'your-app-password',
},
},
defaults: {
from: '"My App" <[email protected]>',
},
template: {
dir: __dirname + '/templates',
adapter: new HandlebarsAdapter(),
},
} as EmailConfig),
],
})
export class AppModule {}Environment Variables
| Variable | Description | Default |
| ------------------------- | ----------------- | --------------------- |
| EMAIL_SMTP | SMTP host | Required |
| EMAIL_SMTP_PORT | SMTP port | 587 |
| EMAIL_SMTP_USERNAME | SMTP username | Required |
| EMAIL_SMTP_PASSWORD | SMTP password | Required |
| EMAIL_SMTP_DISPLAY_NAME | Default from name | [email protected] |
SMTP Ports
| Port | Use | Secure |
| ------ | ----------- | -------- |
| 25 | Legacy | No |
| 465 | SMTPS | Yes |
| 587 | Submission | No (TLS) |
| 2525 | Alternative | No |
Common Email Patterns
Welcome Email
async sendWelcomeEmail(user: User) {
await this.mailerService.sendMail({
to: user.email,
subject: 'Welcome to Our Platform!',
template: 'welcome',
context: {
name: user.firstName,
verifyUrl: `${BASE_URL}/verify/${user.verificationToken}`,
},
});
}Password Reset
async sendPasswordReset(user: User) {
await this.mailerService.sendMail({
to: user.email,
subject: 'Password Reset Request',
template: 'reset-password',
context: {
name: user.name,
resetUrl: `${BASE_URL}/reset-password/${user.resetToken}`,
expiresIn: '1 hour',
},
});
}Invoice Email
async sendInvoice(user: User, invoice: Invoice) {
await this.mailerService.sendMail({
to: user.email,
subject: `Invoice #${invoice.number}`,
template: 'invoice',
context: {
invoiceNumber: invoice.number,
amount: invoice.amount,
dueDate: invoice.dueDate,
items: invoice.items,
total: invoice.total,
},
attachments: [
{
filename: `invoice-${invoice.number}.pdf`,
path: invoice.pdfPath,
},
],
});
}API Reference
EmailModule
// Default configuration from environment
EmailModule.forRoot()
// Custom configuration
EmailModule.forRoot(config: EmailConfig)EmailService
class EmailService {
constructor(private readonly mailerService: MailerService) {}
async sendEmail(options: SendEmailOptions): Promise<SentMessageInfo>;
async verify(): Promise<boolean>;
}SendEmailOptions
interface SendEmailOptions {
to: string | string[];
subject: string;
html?: string;
text?: string;
from?: string;
replyTo?: string;
cc?: string | string[];
bcc?: string | string[];
attachments?: Attachment[];
}Troubleshooting
Q: Emails not sending?
- Check SMTP credentials in environment
- Verify SMTP server is accessible
- Test connection:
await emailService.verify()
Q: Templates not found?
Ensure templates are in process.cwd() + '/templates/':
// Check template path
console.log(process.cwd() + '/templates/');Q: Handlebars syntax errors?
Enable strict mode to see detailed errors:
template: {
options: { strict: true },
}Q: Gmail authentication fails?
If using Gmail with 2FA, create an App Password:
- Google Account → Security
- 2-Step Verification → App Passwords
- Generate new app password for your app
Related Packages
None - standalone email package
License
ISC
