1.0.6 • Published 10 months ago
@c1x/nest-mailer v1.0.6
@c1x/nest-mailer
A flexible and easy-to-use mailer module for NestJS applications, supporting multiple email providers including SMTP, AWS SES, and SendGrid.
Features
- 📧 Multiple provider support (SMTP, AWS SES, SendGrid)
- ⚙️ Environment-based configuration
- 🚀 Asynchronous module configuration
- 📎 Attachment support
- 🎨 HTML email support
- 💪 Type-safe implementation
- 🔍 Detailed error logging
Installation
npm install @c1x/nest-mailerQuick Start
- Import the MailerModule in your app.module.ts:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MailerModule } from '@c1x/nest-mailer';
import { join } from 'path';
@Module({
imports: [
ConfigModule.forRoot(),
MailerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
// Required: Provider configuration
provider: configService.get('MAIL_PROVIDER', 'sendgrid'),
credentials: {
apiKey: configService.get('SENDGRID_API_KEY'),
},
// Optional: Template configuration
templatesDir: join(__dirname, 'templates'), // Only needed if using templates
}),
}),
],
})
export class AppModule {}- Configure your environment variables:
# Choose your preferred provider and configure accordingly
# SendGrid Configuration
SENDGRID_API_KEY=your_api_key
MAIL_FROM_NAME=Your App Name
MAIL_FROM_ADDRESS=noreply@yourapp.com
# Or SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
# Or AWS SES Configuration
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=your_region- Use the MailerService in your application:
import { Injectable } from '@nestjs/common';
import { MailerService } from '@c1x/nest-mailer';
@Injectable()
export class AppService {
constructor(private readonly mailerService: MailerService) {}
async sendWelcomeEmail(userEmail: string) {
await this.mailerService.sendMail({
to: userEmail,
fromName: 'Your App Name', // New: Separate sender name
fromAddress: 'noreply@yourapp.com', // New: Separate sender email
subject: 'Welcome to Our App!',
text: 'Welcome to our application...',
html: '<h1>Welcome!</h1><p>We're glad to have you on board.</p>',
});
}
}Provider Configuration
SendGrid Configuration
MailerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
provider: 'sendgrid',
credentials: {
apiKey: configService.get('SENDGRID_API_KEY'),
},
// Optional template support
templatesDir: join(__dirname, 'templates'),
}),
}),SMTP Configuration
MailerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
provider: 'smtp',
credentials: {
host: configService.get('SMTP_HOST'),
port: parseInt(configService.get('SMTP_PORT')),
secure: configService.get('SMTP_SECURE') === 'true',
auth: {
user: configService.get('SMTP_USER'),
pass: configService.get('SMTP_PASS'),
},
},
}),
}),AWS SES Configuration
MailerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
provider: 'aws-ses',
credentials: {
accessKeyId: configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'),
region: configService.get('AWS_REGION'),
},
}),
}),API Reference
MailOptions Interface
interface MailOptions {
// Required fields
to: string | string[];
fromName: string; // New: Sender name field
fromAddress: string; // New: Sender email field
subject: string;
// Optional fields
text?: string; // Plain text content
html?: string; // HTML content
template?: string; // Template name (if using templates)
context?: any; // Template variables (if using templates) example context variables {'name':'json','email':'example@gmail.com'}
attachments?: Array<{
filename: string;
content: Buffer | string;
contentType?: string;
cid?: string; // For inline images
}>;
}Provider Configurations
interface SmtpConfig {
host: string;
port: number;
secure: boolean;
auth: {
user: string;
pass: string;
};
}
interface AwsSesConfig {
accessKeyId: string;
secretAccessKey: string;
region: string;
}
interface SendGridConfig {
apiKey: string;
}Error Handling
The module includes built-in error handling. Here's an example of how to handle errors:
try {
await this.mailerService.sendMail({
to: 'user@example.com',
from: 'noreply@yourapp.com',
subject: 'Test Email',
text: 'This is a test email',
});
} catch (error) {
// Handle specific error types
if (error.code === 'EAUTH') {
// Handle authentication error
} else if (error.code === 'ETIMEDOUT') {
// Handle timeout error
}
throw error;
}Sending Emails with Attachments
Here are different examples of sending emails with attachments:
- Send with Buffer attachment:
import { Injectable } from '@nestjs/common';
import { MailerService } from '@c1x/nest-mailer';
import * as fs from 'fs';
@Injectable()
export class EmailService {
constructor(private readonly mailerService: MailerService) {}
async sendWithAttachment() {
// Read file as buffer
const fileBuffer = fs.readFileSync('path/to/file.pdf');
await this.mailerService.sendMail({
to: 'user@example.com',
fromAddress: 'noreply@yourapp.com',
fromName:"test",
subject: 'Document Attached',
text: 'Please find the attached document.',
attachments: [
{
filename: 'document.pdf',
content: fileBuffer,
contentType: 'application/pdf',
}
]
});
}
}- Send with multiple attachments:
@Injectable()
export class EmailService {
constructor(private readonly mailerService: MailerService) {}
async sendWithMultipleAttachments() {
await this.mailerService.sendMail({
to: 'user@example.com',
fromAddress: 'noreply@yourapp.com',
fromName:"test",
subject: 'Multiple Attachments',
text: 'Please find the attached files.',
attachments: [
{
filename: 'report.pdf',
content: fs.readFileSync('path/to/report.pdf'),
contentType: 'application/pdf',
},
{
filename: 'image.jpg',
content: fs.readFileSync('path/to/image.jpg'),
contentType: 'image/jpeg',
},
{
filename: 'data.csv',
content: fs.readFileSync('path/to/data.csv'),
contentType: 'text/csv',
}
]
});
}
}- Inline images in HTML email:
@Injectable()
export class EmailService {
constructor(private readonly mailerService: MailerService) {}
async sendWithInlineImages() {
await this.mailerService.sendMail({
to: 'user@example.com',
fromAddress: 'noreply@yourapp.com',
fromName:"test",
subject: 'Email with Inline Image',
html: `
<h1>Welcome!</h1>
<p>Here's our logo:</p>
<img src="cid:unique-logo-id" />
`,
attachments: [
{
filename: 'logo.png',
content: fs.readFileSync('path/to/logo.png'),
contentType: 'image/png',
cid: 'unique-logo-id' // Content ID for referencing in HTML
}
]
});
}
}- Send with Base64 attachment:
@Injectable()
export class EmailService {
constructor(private readonly mailerService: MailerService) {}
async sendWithBase64Attachment() {
const base64Content = 'base64_encoded_string';
await this.mailerService.sendMail({
to: 'user@example.com',
fromAddress: 'noreply@yourapp.com',
fromName:"test",
subject: 'Image Attached',
html: '<h1>Check out this image!</h1>',
attachments: [
{
filename: 'image.png',
content: base64Content,
contentType: 'image/png',
}
]
});
}
}- Use the MailerService with templates in your application:
import { Injectable } from '@nestjs/common';
import { MailerService } from '@c1x/nest-mailer';
@Injectable()
export class AppService {
constructor(private readonly mailerService: MailerService) {}
async sendWelcomeEmail(userEmail: string, userName: string) {
await this.mailerService.sendMail({
to: userEmail,
fromAddress: 'noreply@yourapp.com',
fromName:"test",
subject: 'Welcome to Our App!',
template: 'welcome', // References welcome.hbs
context: {
appName: 'YourApp',
userName: userName,
welcomeMessage: 'We\'re excited to have you on board!'
}
});
}
}Best Practices
- Always use environment variables for sensitive credentials
- Implement proper error handling
- Use type-safe interfaces provided by the library
- Consider implementing a retry mechanism for failed emails
- Use HTML templates for consistent email styling
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Support
For issues and feature requests, please create an issue in the GitHub repository.