首页 > 解决方案 > Nodemailer:如何正确发送“存储”在文件中的 html 消息?

问题描述

我想通过使用存储为 html 文件而不是“硬编码”消息字符串的消息来简化使用 Nodemailer 发送 html 消息。但是,由于某种原因,Nodemailer 不能像我期望的那样工作。

以下代码运行良好(带有“硬编码”消息字符串的版本):

const nodemailer = require('nodemailer');
const fs = require('fs');

let htmlMessage = "";

// Retrieve message from file
fs.readFile("./Message.html", 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data)
  htmlMessage = data;
});

console.log(htmlMessage);

// 1.) Define "transporter"
const transporter = nodemailer.createTransport({
  service: ...,
  auth: {
    user: ...,
    pass: ...
  }
})

// 2.) Configure email
const email = {
  from: ...,
  text: 'This is a test! (Plain Text)',
  
  // html: htmlMessage

  html: '<div style="margin: 1em; padding: 0.5em; background-color: rgb(90, 168, 90); font-size: 1.5em; '
  + 'border-radius: 0.5em; font-family: Arial, Helvetica, sans-serif;"> '
  + 'This is a test!'
  + '</div>'

};

// 3.) Send email
transporter.sendMail(email, (error, info) => { if (error) {
  console.error(error); } else {
  console.log('Message sent: %s', info.messageId); }
});

但是,如果我像这样更改消息...

// 2.) Configure email
const email = {
  from: ...,
  text: 'This is a test! (Plain Text)',
  html: htmlMessage

  /*
  html: '<div style="margin: 1em; padding: 0.5em; background-color: rgb(90, 168, 90); font-size: 1.5em; '
  + 'border-radius: 0.5em; font-family: Arial, Helvetica, sans-serif;"> '
  + 'This is a test!'
  + '</div>'
  */
};

...并用此文件替换“硬编码”字符串...

消息.html

<div style="margin: 1em;
  padding: 0.5em;
  background-color: rgb(90, 168, 90);
  font-size: 1.5em;
  border-radius: 0.5em;
  font-family: Arial, Helvetica, sans-serif;">
  This is a test!
</div>

...发送 html 内容不再起作用。我只收到“纯文本版本”。由于某种原因,Nodemailer 失败了。我究竟做错了什么?

标签: node.jsnodemailer

解决方案


您的问题是初学者对异步代码的常见误解之一。

在您的代码中,您这样做了:

let htmlMessage = "";

// 1.) Retrieve message from file
fs.readFile("./Message.html", 'utf8', (err, data) => {

  // 3.) Callback completes
  if (err) throw err;
  console.log(data)
  htmlMessage = data;
});

// ....

console.log(htmlMessage); // SHOULD show empty string

// 2.) Configure email
const email = {
  from: ...,
  text: 'This is a test! (Plain Text)',
  html: htmlMessage
};

如您所见,代码您发送电子邮件1.)后的2.)几毫秒内执行。在阅读 HTML 文件之前,您基本上已经发送了电子邮件。3.)

你需要做的是:

let htmlMessage = "";

// 1.) Retrieve message from file
fs.readFile("./Message.html", 'utf8', (err, data) => {

  // 2.) Callback completes
  if (err) throw err;
  console.log(data)
  htmlMessage = data;

  // ...

  // 3.) Configure email
  const email = {
    from: ...,
    text: 'This is a test! (Plain Text)',
    html: htmlMessage
  };
});

或者,如果您更喜欢阅读原始代码的流程,您可以承诺fs.readFile()并使用async/await

const util = require('util');

const readFile = util.promisify(fs.readFile);

async function foo () {

  // 1.) Retrieve message from file
  let htmlMessage = await readFile("./Message.html", 'utf8');

  // ....

  // 2.) Configure email
  const email = {
    from: ...,
    text: 'This is a test! (Plain Text)',
    html: htmlMessage
  };
}

foo();

推荐阅读