You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@nestjs-modules/mailer含废弃包(vm2),如何安全用NestJS发邮件?

在NestJS中安全发送邮件的靠谱方案(替代废弃的@nestjs-modules/mailer)

为什么必须换掉@nestjs-modules/mailer

该库存在严重安全问题,请勿用于生产环境!项目已停止维护,建议迁移至isolated-vm。

这个提示已经说得很明确:这个包不仅停止维护,还存在严重安全漏洞,绝对不能用于生产环境,直接弃用即可。

推荐方案:直接集成Nodemailer

Nodemailer是Node.js生态中最成熟、维护最活跃的邮件发送库,完全可以直接在NestJS中使用,无需依赖第三方封装的废弃包,安全可靠且灵活。

步骤1:安装依赖

先安装Nodemailer本身,以及TypeScript项目所需的类型定义:

npm install nodemailer
npm install --save-dev @types/nodemailer

步骤2:封装邮件服务

在NestJS中创建一个MailService,将Nodemailer的逻辑封装起来,符合Nest的模块化规范,方便后续复用:

// src/mail/mail.service.ts
import { Injectable } from '@nestjs/common';
import * as nodemailer from 'nodemailer';

@Injectable()
export class MailService {
  private transporter: nodemailer.Transporter;

  constructor() {
    // 用环境变量存储敏感配置,生产环境必须遵循此规范
    this.transporter = nodemailer.createTransport({
      host: process.env.MAIL_HOST,
      port: parseInt(process.env.MAIL_PORT, 10),
      secure: process.env.MAIL_SECURE === 'true', // true对应465端口(SSL加密),false对应587端口(STARTTLS加密)
      auth: {
        user: process.env.MAIL_USER,
        pass: process.env.MAIL_PASS,
      },
    });

    // 可选:启动时验证配置是否正确,提前排查问题
    this.transporter.verify((error, success) => {
      if (error) {
        console.error('邮件服务配置错误:', error);
      } else {
        console.log('邮件服务已准备就绪');
      }
    });
  }

  async sendMail(to: string, subject: string, html: string) {
    const mailOptions = {
      from: process.env.MAIL_FROM, // 发件人格式可设为「应用名称 <邮箱地址>」
      to,
      subject,
      html,
    };

    try {
      await this.transporter.sendMail(mailOptions);
      console.log(`邮件已成功发送至 ${to}`);
    } catch (error) {
      console.error(`发送邮件至 ${to} 失败:`, error);
      throw error; // 抛出错误供上层处理,比如返回前端错误提示
    }
  }
}

步骤3:注册邮件模块

创建对应的模块文件,将MailService注册为可注入服务,并导出供其他模块使用:

// src/mail/mail.module.ts
import { Module } from '@nestjs/common';
import { MailService } from './mail.service';

@Module({
  providers: [MailService],
  exports: [MailService], // 导出后其他模块可直接注入使用
})
export class MailModule {}

随后在根模块AppModule中导入该模块,同时加载环境变量(借助@nestjs/config简化配置读取):

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MailModule } from './mail/mail.module';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }), // 全局加载环境变量,无需每个模块重复导入
    MailModule,
  ],
})
export class AppModule {}

步骤4:配置环境变量

在项目根目录创建.env文件(务必将此文件加入.gitignore,避免敏感信息泄露),填写邮件服务的具体配置:

# 示例:QQ邮箱填smtp.qq.com,Gmail填smtp.gmail.com
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_SECURE=false
MAIL_USER=your-email@example.com
# 注意:Gmail、QQ邮箱等需使用应用专用密码,而非日常登录密码
MAIL_PASS=your-app-specific-password
MAIL_FROM='你的应用名称 <your-email@example.com>'

业务中使用邮件服务

比如用户注册时发送确认邮件,在控制器中注入MailService直接调用即可:

// src/user/user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { MailService } from '../mail/mail.service';

@Controller('users')
export class UserController {
  constructor(private readonly mailService: MailService) {}

  @Post('register')
  async register(@Body() userData: { email: string }) {
    // 先执行用户注册逻辑,如写入数据库等

    // 发送注册确认邮件
    await this.mailService.sendMail(
      userData.email,
      '欢迎注册!请完成验证',
      `<h1>嗨,${userData.email}!</h1><p>感谢注册我们的应用,点击<a href="你的验证链接">这里</a>完成账号验证...</p>`,
    );

    return { message: '注册成功,确认邮件已发送至你的邮箱' };
  }
}

生产环境安全注意事项

  • 敏感信息保密:邮箱密码、SMTP地址等绝对不能硬编码,必须使用环境变量或专业密钥管理工具(如AWS Secrets Manager)。
  • 加密传输:优先使用465端口(SSL加密)或587端口(STARTTLS加密),避免明文传输邮件内容。
  • 限流防封禁:添加限流机制,比如同一用户1分钟内最多发送2封邮件,防止被邮件服务商判定为垃圾邮件。
  • 完善错误处理:添加邮件发送失败的重试逻辑,避免因临时网络问题导致重要邮件丢失。

内容的提问来源于stack exchange,提问作者José Useche C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:25:55