Nodemailer 入门指南:轻松实现 Node.js 邮件发送

Nodemailer 入门指南:轻松实现 Node.js 邮件发送

前言

邮件发送功能是很多应用程序的必备功能(尤其是那些需要用户注册、密码重置或通知系统的应用)。在 Node.js 生态系统中,Nodemailer 无疑是最受欢迎、最可靠的邮件发送库!!!它简单易用,功能又足够强大,让开发者能够快速集成邮件功能到自己的应用中。

我第一次使用 Nodemailer 是在构建一个需要发送注册确认邮件的网站时。当时被它的简洁API和丰富的功能所震撼。今天就让我带你一起探索这个强大的工具,从零开始学习如何使用 Nodemailer 发送各种类型的邮件。

Nodemailer 是什么?

Nodemailer 是一个专为 Node.js 设计的邮件发送模块,由 Andris Reinman 创建于2010年。多年来,它已经成为 Node.js 社区中发送邮件的标准解决方案。它支持从简单的纯文本邮件到复杂的 HTML 内容,甚至可以添加附件和嵌入图片。

主要特点包括:

  • 易于使用的 API
  • Unicode 支持
  • HTML 内容支持
  • 附件支持(包括数据流)
  • 安全的邮件发送(TLS/SSL)
  • 支持各种邮件服务提供商
  • 可自定义邮件头
  • 支持 SMTP 和其他传输方式

安装 Nodemailer

在开始之前,确保你已经安装了 Node.js 环境。然后,在你的项目目录中运行以下命令:

npm install nodemailer

就这么简单!一行命令就把 Nodemailer 添加到你的项目中了。

基础使用:发送一封简单的邮件

让我们从最基础的开始 - 发送一封简单的文本邮件。

const nodemailer = require('nodemailer');

// 创建一个SMTP传输对象
const transporter = nodemailer.createTransport({
  service: 'gmail',  // 使用预定义的服务
  auth: {
    user: 'your.email@gmail.***',
    pass: 'your-password-or-app-password'
  }
});

// 定义邮件选项
const mailOptions = {
  from: 'your.email@gmail.***',
  to: 'recipient@example.***',
  subject: '你好!这是一封测试邮件',
  text: '如果你能看到这个消息,说明Nodemailer运行正常!'
};

// 发送邮件
transporter.sendMail(mailOptions, (error, info) => {
  if (error) {
    return console.error('发送失败:', error);
  }
  console.log('邮件已发送:', info.response);
});

这段代码做了几件事:

  1. 导入 Nodemailer 模块
  2. 创建一个传输对象(配置发送邮件的服务器信息)
  3. 定义邮件内容(发件人、收件人、主题和正文)
  4. 使用 sendMail 方法发送邮件

不过等等!上面的例子使用了 Gmail 作为邮件服务,如果你真的要用 Gmail,可能会遇到一些问题(特别是安全设置)。Gmail 现在默认不允许"不安全应用程序"访问,所以你需要生成"应用专用密码"或者调整设置。

使用其他邮件服务提供商

除了 Gmail,Nodemailer 还支持多种邮件服务提供商。你可以使用 SMTP 配置来连接几乎任何邮件服务:

const transporter = nodemailer.createTransport({
  host: 'smtp.example.***',
  port: 587,
  secure: false, // true用于465端口,false用于其他端口
  auth: {
    user: 'username@example.***',
    pass: 'password'
  }
});

常见邮件服务的配置:

  • Outlook/Hotmail:

    host: 'smtp-mail.outlook.***',
    port: 587,
    secure: false
    
  • QQ邮箱:

    host: 'smtp.qq.***',
    port: 465,
    secure: true
    
  • 163邮箱:

    host: 'smtp.163.***',
    port: 465,
    secure: true
    

发送HTML格式邮件

纯文本邮件有点单调,对吧?让我们升级一下,发送HTML格式的邮件:

const mailOptions = {
  from: 'your.email@example.***',
  to: 'recipient@example.***',
  subject: '漂亮的HTML邮件',
  html: `
    <h1>欢迎使用Nodemailer!</h1>
    <p>这是一封<b>HTML格式</b>的邮件,你可以添加:</p>
    <ul>
      <li>标题</li>
      <li>列表</li>
      <li>甚至是<a href="https://example.***">链接</a></li>
    </ul>
    <p>是不是很酷?</p>
  `
};

使用 html 属性而不是 text 属性,就可以发送HTML格式的邮件了。当然,你也可以同时设置两者,这样在不支持HTML的邮件客户端中会显示纯文本内容。

添加附件

需要发送文件?Nodemailer 让添加附件变得超级简单:

const mailOptions = {
  from: 'your.email@example.***',
  to: 'recipient@example.***',
  subject: '带附件的邮件',
  text: '请查看附件!',
  attachments: [
    {
      filename: '文档.pdf',
      path: '/path/to/document.pdf'
    },
    {
      filename: '图片.jpg',
      path: '/path/to/image.jpg'
    }
  ]
};

你甚至可以直接使用Buffer或Stream作为附件:

attachments: [
  {
    filename: '生成的文本.txt',
    content: Buffer.from('这是一个动态生成的文本文件')
  },
  {
    filename: '网络图片.jpg',
    path: 'https://example.***/some-image.jpg'
  }
]

发送给多个收件人

要发送给多个收件人,只需在 to 字段中用逗号分隔邮箱地址:

const mailOptions = {
  from: 'your.email@example.***',
  to: 'recipient1@example.***, recipient2@example.***, recipient3@example.***',
  subject: '群发邮件',
  text: '这封邮件发给了多个人!'
};

如果你想使用抄送(***)或密送(B***)功能:

const mailOptions = {
  from: 'your.email@example.***',
  to: 'main-recipient@example.***',
  ***: 'copy-recipient@example.***',
  b***: 'hidden-recipient@example.***',
  subject: '使用***和B***',
  text: '主收件人可以看到***,但看不到B***的收件人。'
};

在HTML邮件中嵌入图片

想在HTML邮件中嵌入图片,而不是作为附件发送?Nodemailer也能轻松实现:

const mailOptions = {
  from: 'your.email@example.***',
  to: 'recipient@example.***',
  subject: '带嵌入图片的邮件',
  html: `
    <h1>看看这张漂亮的图片!</h1>
    <img src="cid:unique-image-id">
  `,
  attachments: [
    {
      filename: 'image.jpg',
      path: '/path/to/image.jpg',
      cid: 'unique-image-id' // 与HTML中的src匹配
    }
  ]
};

关键是使用 cid (Content ID) 属性,HTML中的图片引用这个ID,而不是外部URL。

使用模板引擎

对于复杂的邮件内容,手写HTML不是最佳选择。更好的方法是使用模板引擎,比如 EJS、Handlebars 或 Pug。

以 EJS 为例:

  1. 安装 EJS:
npm install ejs
  1. 创建一个邮件模板 (email-template.ejs):
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>邮件通知</title>
</head>
<body>
  <h1>你好,<%= name %>!</h1>
  <p>感谢你注册我们的服务。</p>
  <% if (verificationRequired) { %>
    <p>请点击下面的链接验证你的邮箱:</p>
    <a href="<%= verificationLink %>">验证邮箱</a>
  <% } %>
  <p>祝好,<br>团队</p>
</body>
</html>
  1. 在代码中使用模板:
const ejs = require('ejs');
const path = require('path');

// 渲染邮件模板
ejs.renderFile(
  path.join(__dirname, 'email-template.ejs'),
  { 
    name: '张三', 
    verificationRequired: true,
    verificationLink: 'https://example.***/verify?token=abc123'
  },
  (err, html) => {
    if (err) {
      console.error('模板渲染错误:', err);
      return;
    }
    
    // 使用渲染后的HTML发送邮件
    const mailOptions = {
      from: 'your.email@example.***',
      to: 'recipient@example.***',
      subject: '欢迎注册',
      html: html
    };
    
    transporter.sendMail(mailOptions, (error, info) => {
      if (error) {
        return console.error('发送失败:', error);
      }
      console.log('邮件已发送:', info.response);
    });
  }
);

这种方式可以让你的邮件内容更加动态和可维护。

处理不同的邮件场景

让我们看看几个常见的邮件发送场景:

1. 欢迎邮件

function sendWel***eEmail(user) {
  const mailOptions = {
    from: 'your-app@example.***',
    to: user.email,
    subject: `欢迎加入,${user.name}`,
    html: `
      <h1>欢迎来到我们的平台!</h1>
      <p>亲爱的 ${user.name},</p>
      <p>感谢你注册我们的服务。我们很高兴有你的加入!</p>
      <p>如果你有任何问题,可以直接回复这封邮件。</p>
      <p>祝你使用愉快!</p>
    `
  };
  
  return transporter.sendMail(mailOptions);
}

2. 密码重置邮件

function sendPasswordResetEmail(user, resetToken) {
  const resetUrl = `https://yourapp.***/reset-password?token=${resetToken}`;
  
  const mailOptions = {
    from: 'security@yourapp.***',
    to: user.email,
    subject: '密码重置请求',
    html: `
      <h1>密码重置</h1>
      <p>亲爱的用户,</p>
      <p>我们收到了你的密码重置请求。如果这不是你发起的,请忽略此邮件。</p>
      <p>点击下面的链接重置密码(链接24小时内有效):</p>
      <a href="${resetUrl}">重置密码</a>
      <p>出于安全原因,此链接将在24小时后失效。</p>
    `
  };
  
  return transporter.sendMail(mailOptions);
}

3. 订单确认邮件

function sendOrderConfirmation(order, user) {
  // 生成订单项目的HTML
  const itemsHtml = order.items.map(item => `
    <tr>
      <td>${item.name}</td>
      <td>${item.quantity}</td>
      <td>¥${item.price.toFixed(2)}</td>
      <td>¥${(item.price * item.quantity).toFixed(2)}</td>
    </tr>
  `).join('');
  
  const mailOptions = {
    from: 'orders@yourstore.***',
    to: user.email,
    subject: `订单 #${order.id} 确认`,
    html: `
      <h1>感谢你的订购!</h1>
      <p>亲爱的 ${user.name},</p>
      <p>我们已收到你的订单(订单号:${order.id})。</p>
      
      <h2>订单详情:</h2>
      <table border="1" cellpadding="5" cellspacing="0">
        <tr>
          <th>商品</th>
          <th>数量</th>
          <th>单价</th>
          <th>小计</th>
        </tr>
        ${itemsHtml}
        <tr>
          <td colspan="3" align="right"><strong>总计:</strong></td>
          <td>¥${order.total.toFixed(2)}</td>
        </tr>
      </table>
      
      <p>预计发货时间:${order.estimatedShippingDate}</p>
      <p>如有问题,请联系我们的客服团队。</p>
    `
  };
  
  return transporter.sendMail(mailOptions);
}

使用Promise和Async/Await

Nodemailer的sendMail方法支持回调和Promise。如果你喜欢更现代的异步代码风格,可以这样使用:

// 使用Promise
transporter.sendMail(mailOptions)
  .then(info => {
    console.log('邮件已发送:', info.response);
  })
  .catch(error => {
    console.error('发送失败:', error);
  });

// 或者使用async/await
async function sendEmail() {
  try {
    const info = await transporter.sendMail(mailOptions);
    console.log('邮件已发送:', info.response);
    return info;
  } catch (error) {
    console.error('发送失败:', error);
    throw error;
  }
}

测试邮件发送

在开发阶段,你可能不想真的发送邮件。Nodemailer提供了一个很棒的测试工具 - Ethereal Email。

async function main() {
  // 创建测试账户
  const testA***ount = await nodemailer.createTestA***ount();

  // 创建测试用的传输对象
  const transporter = nodemailer.createTransport({
    host: 'smtp.ethereal.email',
    port: 587,
    secure: false,
    auth: {
      user: testA***ount.user,
      pass: testA***ount.pass
    }
  });

  // 发送邮件
  const info = await transporter.sendMail({
    from: '"测试发件人" <test@example.***>',
    to: 'recipient@example.***',
    subject: '测试邮件',
    text: '这是一封测试邮件',
    html: '<b>这是一封测试邮件</b>'
  });

  console.log('邮件已发送: %s', info.messageId);
  // 预览URL (仅适用于Ethereal邮箱)
  console.log('预览URL: %s', nodemailer.getTestMessageUrl(info));
}

main().catch(console.error);

这样,你就可以在不实际发送邮件的情况下测试你的邮件功能。Ethereal会捕获这些邮件,并提供一个网页链接让你查看邮件的样子。

处理常见问题

认证失败

如果遇到"Authentication failed"错误:

  1. 检查用户名和密码是否正确
  2. 对于Gmail,确保启用了"低安全性应用访问"或使用应用专用密码
  3. 确认你的邮件服务提供商没有封锁SMTP访问

发送速率限制

大多数邮件服务提供商都有发送速率限制。如果你需要发送大量邮件,考虑:

  1. 实现队列系统,控制发送速率
  2. 使用专业的邮件发送服务,如SendGrid、Mailgun或Amazon SES
// 简单的邮件队列示例
const emailQueue = [];
let isSending = false;

function addToQueue(mailOptions) {
  emailQueue.push(mailOptions);
  if (!isSending) {
    processQueue();
  }
}

async function processQueue() {
  if (emailQueue.length === 0) {
    isSending = false;
    return;
  }
  
  isSending = true;
  const mail = emailQueue.shift();
  
  try {
    await transporter.sendMail(mail);
    console.log('邮件已发送');
  } catch (error) {
    console.error('发送失败:', error);
  }
  
  // 延迟一秒后发送下一封,避免超过发送限制
  setTimeout(processQueue, 1000);
}

邮件被标记为垃圾邮件

为减少被标记为垃圾邮件的可能性:

  1. 使用SPF和DKIM验证(需要域名DNS配置)
  2. 避免使用过多的感叹号和全大写单词
  3. 确保HTML和文本内容都存在
  4. 不要发送未经请求的邮件
  5. 提供明确的退订选项

结语

Nodemailer 是一个功能强大又易于使用的邮件发送库,它极大地简化了在 Node.js 应用中集成邮件功能的过程。从简单的文本邮件到复杂的 HTML 邮件,从单个收件人到批量发送,Nodemailer 都能应对自如。

希望这篇入门指南能帮助你快速上手 Nodemailer!随着你的深入使用,你会发现它还有更多高级功能可以探索,比如事件处理、插件系统等。

记住,好的邮件不仅仅是技术问题 - 内容、时机和相关性同样重要。无论你是用它来发送注册确认、密码重置链接,还是营销通讯,都要确保你的邮件是用户期望收到的,并提供真正的价值。

祝你编码愉快!

转载请说明出处内容投诉
CSS教程网 » Nodemailer 入门指南:轻松实现 Node.js 邮件发送

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买