在NestJS中使用AWS SES同时发送PDF附件与HTML模板邮件
在NestJS中使用AWS SES同时发送HTML模板邮件与PDF附件
AWS SES的sendTemplatedEmail确实不支持直接添加附件,要同时实现HTML模板渲染和PDF附件,你需要用sendRawEmail方法,自己构建包含渲染后HTML内容和附件的MIME格式邮件。下面是具体实现步骤和代码示例:
实现步骤
- 先渲染你的HTML模板为最终的HTML字符串
- 构建符合MIME标准的邮件内容,包含HTML正文、PDF附件、发件人/收件人/主题等信息
- 调用SES的
sendRawEmail接口发送邮件
代码示例
1. 模板渲染(以Handlebars为例)
先安装依赖:
npm install handlebars @nestjs/handlebars
在NestJS模块中配置Handlebars:
import { Module } from '@nestjs/common'; import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter'; import { MailerModule } from '@nestjs-modules/mailer'; import { join } from 'path'; @Module({ imports: [ MailerModule.forRoot({ defaults: { from: '"Your App" <your-email@example.com>', }, template: { dir: join(__dirname, 'templates'), adapter: new HandlebarsAdapter(), options: { strict: true, }, }, }), ], }) export class MailModule {}
在Service中封装模板渲染逻辑:
import { Injectable } from '@nestjs/common'; import { MailerService } from '@nestjs-modules/mailer'; @Injectable() export class TemplateRenderService { constructor(private readonly mailerService: MailerService) {} async render(templateName: string, context: any): Promise<string> { return this.mailerService.render(templateName, context); } }
2. 构建MIME邮件内容并发送
使用nodemailer来构建MIME消息(比手动拼接更可靠),先安装依赖:
npm install nodemailer aws-sdk
在Service中实现核心发送逻辑:
import { Injectable } from '@nestjs/common'; import { SES } from 'aws-sdk'; import * as nodemailer from 'nodemailer'; import { TemplateRenderService } from './template-render.service'; @Injectable() export class SesEmailService { private ses: SES; constructor(private readonly templateRender: TemplateRenderService) { this.ses = new SES({ region: 'your-aws-region', // 如us-east-1 accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }); } async sendTemplatedWithAttachment( to: string[], subject: string, templateName: string, templateContext: any, pdfBuffer: Buffer, pdfFileName: string, ) { // 1. 渲染HTML模板 const htmlContent = await this.templateRender.render(templateName, templateContext); // 2. 用nodemailer生成MIME格式字符串 const transporter = nodemailer.createTransport({ SES: { ses: this.ses, aws: require('aws-sdk') }, }); const rawMessage = await transporter.sendMail({ from: '"Your App" <your-email@example.com>', to, subject, html: htmlContent, attachments: [ { filename: pdfFileName, content: pdfBuffer, contentType: 'application/pdf', }, ], raw: true, // 仅生成MIME内容,不实际发送 }); // 3. 调用SES的sendRawEmail接口发送 const params = { RawMessage: { Data: rawMessage, }, }; return this.ses.sendRawEmail(params).promise(); } }
3. 使用示例(搭配PDF生成)
假设用pdfkit生成PDF:
import { Injectable } from '@nestjs/common'; import { SesEmailService } from './ses-email.service'; import * as PDFDocument from 'pdfkit'; @Injectable() export class InvoiceService { constructor(private readonly sesEmail: SesEmailService) {} async sendCustomerInvoice(to: string) { // 生成PDF Buffer const pdfBuffer = await this.generateInvoicePdf(); // 触发邮件发送 await this.sesEmail.sendTemplatedWithAttachment( [to], '您的账单已生成', 'invoice', // templates目录下的invoice.hbs模板 { userName: 'John Doe', invoiceAmount: 99.99 }, pdfBuffer, '2024-invoice.pdf', ); } private async generateInvoicePdf(): Promise<Buffer> { return new Promise((resolve) => { const doc = new PDFDocument(); const buffers: Buffer[] = []; doc.on('data', buffers.push.bind(buffers)); doc.on('end', () => resolve(Buffer.concat(buffers))); doc.text('Customer Invoice', { align: 'center', size: 16 }); doc.text(`Name: John Doe`, { marginTop: 20 }); doc.text(`Amount: $99.99`); doc.end(); }); } }
关键说明
sendTemplatedEmail仅支持AWS预定义模板,无附件扩展能力,因此必须用sendRawEmail实现混合需求- 用
nodemailer生成MIME内容可避免手动拼接的格式错误,提升可靠性 - 确保AWS SES账号已验证发件人邮箱/域名,收件人邮箱处于已验证列表(或账号已脱离沙箱环境)
内容的提问来源于stack exchange,提问作者ashraf ali
相关产品推荐
相关产品推荐

