1.0.6 • Published 1 year ago

@c1x/nest-mailer v1.0.6

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

@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-mailer

Quick Start

  1. 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 {}
  1. 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
  1. 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:

  1. 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',
        }
      ]
    });
  }
}
  1. 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',
        }
      ]
    });
  }
}
  1. 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
        }
      ]
    });
  }
}
  1. 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',
        }
      ]
    });
  }
}
  1. 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

  1. Always use environment variables for sensitive credentials
  2. Implement proper error handling
  3. Use type-safe interfaces provided by the library
  4. Consider implementing a retry mechanism for failed emails
  5. 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.

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

0.0.11

1 year ago

0.0.10

1 year ago

0.0.8

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago