企业级邮件发送:AWS SESv2 + S3 + Raw Email 高级实践

30 阅读3分钟

企业级邮件发送:AWS SESv2 + S3 + Raw Email 高级实践

在现代企业应用中,发送高质量邮件不仅仅是发送文本,而是需要 HTML 模板、多语言支持、附件、内嵌图片 等功能。本文将介绍如何使用 AWS SESv2 + S3 + Raw Email 构建企业级邮件发送方案。


目录

  1. 背景与挑战
  2. 技术方案概览
  3. HTML 模板与变量渲染
  4. 构建 Raw Email
  5. 附件与图片内嵌处理
  6. 完整 Node.js 示例
  7. 最佳实践与注意事项
  8. 总结

背景与挑战

企业邮件发送通常面临以下问题:

  • HTML 模板复杂,含表格、CSS、MJML 注释
  • 占位符需要动态替换
  • 邮件客户端兼容性差(Gmail、Outlook、Apple Mail)
  • 附件 PDF 或图片需要安全发送
  • SES 默认 sendEmail API 不支持完整控制 MIME 结构

解决方案:使用 SESv2 + Raw Email + Base64 编码,结合 S3 存储模板或附件,实现企业级邮件发送。


技术方案概览

整体流程如下:

  1. 模板存储

    • HTML 模板或 MJML 文件存储在 S3
    • 模板中包含占位符,如 {{client_email}}{{invoice_id}}
  2. 模板渲染

    • 使用 MJML → Handlebars
    • 填充占位符生成 HTML 内容
  3. Raw Email 构建

    • 使用 multipart/alternative 包含 text/plain 与 text/html
    • 使用 Content-Transfer-Encoding: base64 避免 HTML 被破坏
  4. 发送邮件

    • SESv2 sendRawEmail API
    • 可添加附件(multipart/mixed)或内嵌图片

HTML 模板与变量渲染

示例 MJML 模板

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-text font-size="16px" font-weight="bold">
          Dear {{client_email}},
        </mj-text>
        <mj-text>
          Please find attached invoice <b>#{{invoice_id}}</b> for service on <b>{{date}}</b>.
        </mj-text>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

使用 Handlebars 渲染变量

import mjml2html from "mjml";
import Handlebars from "handlebars";

const mjmlTemplate = /* 从 S3 获取模板内容 */;
const html = mjml2html(mjmlTemplate).html;

const data = {
  client_email: "alice@example.com",
  invoice_id: "12345",
  date: "2025-11-20"
};

const htmlContent = Handlebars.compile(html)(data);

✅ 确保 HTML 中的占位符被替换,否则邮箱客户端可能显示为空白。


构建 Raw Email

SES sendRawEmail 需要完整 MIME 结构:

const boundary = "----=_Part_Boundary_123456";

const rawEmail = [
  `From: sender@example.com`,
  `To: recipient@example.com`,
  `Subject: Your Invoice`,
  `MIME-Version: 1.0`,
  `Content-Type: multipart/alternative; boundary="${boundary}"`,
  ``,
  `--${boundary}`,
  `Content-Type: text/plain; charset=UTF-8`,
  `Content-Transfer-Encoding: base64`,
  ``,
  Buffer.from(textContent).toString("base64"),
  `--${boundary}`,
  `Content-Type: text/html; charset=UTF-8`,
  `Content-Transfer-Encoding: base64`,
  ``,
  Buffer.from(htmlContent).toString("base64"),
  `--${boundary}--`,
].join("\r\n");

注意:使用 base64 编码可避免 HTML 被破坏。


附件与图片内嵌处理

  • PDF 或 Excel 附件:使用 multipart/mixed,每个附件都用 Base64 编码
  • 内嵌图片:使用 Content-ID 引用 <img src="cid:xxx">

示例:

--MIXED_BOUNDARY
Content-Type: application/pdf; name="invoice.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="invoice.pdf"

<base64 PDF 内容>
--MIXED_BOUNDARY--

完整 Node.js 示例

import { SESv2Client, SendEmailCommand } from "@aws-sdk/client-sesv2";
import mjml2html from "mjml";
import Handlebars from "handlebars";

const mjmlTemplate = `...`; // 从 S3 获取
const data = { client_email: "alice@example.com", invoice_id: "12345", date: "2025-11-20" };
const htmlContent = Handlebars.compile(mjml2html(mjmlTemplate).html)(data);
const textContent = `Dear ${data.client_email}, Invoice #${data.invoice_id} on ${data.date}\nKind Regards,\neSIMfx Team`;

const boundary = "----=_Part_Boundary_123456";
const rawEmail = [
  `From: sender@example.com`,
  `To: recipient@example.com`,
  `Subject: Your Invoice`,
  `MIME-Version: 1.0`,
  `Content-Type: multipart/alternative; boundary="${boundary}"`,
  "",
  `--${boundary}`,
  `Content-Type: text/plain; charset=UTF-8`,
  `Content-Transfer-Encoding: base64`,
  "",
  Buffer.from(textContent).toString("base64"),
  `--${boundary}`,
  `Content-Type: text/html; charset=UTF-8`,
  `Content-Transfer-Encoding: base64`,
  "",
  Buffer.from(htmlContent).toString("base64"),
  `--${boundary}--`,
].join("\r\n");

const client = new SESv2Client({ region: "us-east-1" });
await client.send(
  new SendEmailCommand({
    FromEmailAddress: "sender@example.com",
    Destination: { ToAddresses: ["recipient@example.com"] },
    Content: { Raw: { Data: Buffer.from(rawEmail) } },
  })
);
console.log("Email sent successfully!");

最佳实践与注意事项

  1. Base64 编码 HTML 避免邮件客户端解析失败
  2. 使用 multipart/alternative 支持纯文本 fallback
  3. 占位符必须渲染完毕,否则空白邮件
  4. 附件也用 Base64,保证传输安全
  5. MJML → HTML → Handlebars,保持模板可维护性

总结

使用 SESv2 + S3 + Raw Email 结合 MJML + Handlebars + Base64 可以实现:

  • 企业级 HTML 邮件发送
  • 多占位符动态渲染
  • 附件与图片内嵌
  • 跨客户端兼容(Gmail/Outlook/Apple Mail)

这是企业级邮件发送的标准做法,既安全又可扩展。