【问题标题】:How to use a hbs template on Firebase Storage with nodemailer-express-handlebars in a database onCreate trigger function?如何在 Firebase 存储上使用 hbs 模板和数据库 onCreate 触发器函数中的 nodemailer-express-handlebars?
【发布时间】:2019-05-22 21:26:25
【问题描述】:

我正在尝试使用通过 nodemailer 上传到我的 firebase 项目存储 (appId.appspot.com/templates/testTemplate.hbs) 的车把模板文件,以便在实时数据库节点上触发 onCreate 函数时发送电子邮件。

我可以使用 html 格式的字符串成功发送电子邮件,但确实需要使用模板将动态数据添加到电子邮件中。

这是我的功能:

import * as functions from "firebase-functions";
const admin = require("firebase-admin");
const hbs = require("nodemailer-express-handlebars");
const nodemailer = require("nodemailer");

const smtpConfig = {
  host: "mailHost",
  port: 465,
  secure: true,
  auth: {
    user: "xxxxxxxx",
    pass: "xxxxxxxx"
  }
};

const transporter = nodemailer.createTransport(smtpConfig);

exports.sendEmail = functions.database
  .ref("/databasePath/{pushId}")
  .onCreate(async (snapshot, context) => {
    const userData = snapshot.val();
    admin.initializeApp({
      storageBucket: "appId.appspot.com"
    });
    const bucket = admin.storage().bucket();
    const templatesFolder = bucket.name + "/templates/"; // path to storage folder with templates

    transporter.use(
      "compile",
      hbs({
        viewPath: templatesFolder,
        extName: ".hbs"
      })
    );
    const uniqueCode = "generated by a function";
    const uniqueLink = "https://appId.firebaseapp.com/?id=" + uniqueCode;
    const message = {
      from: "fromEmail",
      to: "toEmail",
      subject: "Subject",
      template: "testTemplate", // name of the template file
      context: {
        user: "User name",
        link: uniqueLink
      }
    };

    try {
      await transporter.sendMail(message);
      console.log("Email sent to:", "toEmail");
    } catch (error) {
      console.error("Error sending email:", error);
    }
    return null;
  });

触发该功能时,我在日志中收到以下错误:

发送电子邮件时出错:{ 错误:ENOENT:没有这样的文件或目录,打开 '/user_code/appId.appspot.com/templates/testTemplate.hbs' 在错误(本机) 错误号:-2, 代码:'ENOENT', 系统调用:'打开', 路径:'/user_code/appId.appspot.com/templates/testTemplate.hbs' }

bucket.name 开头有“/user_code”,因此 hbs 找不到模板。如何获得模板文件夹的正确路径?

【问题讨论】:

    标签: firebase firebase-realtime-database firebase-authentication google-cloud-functions nodemailer


    【解决方案1】:

    看起来您实际上并未编写任何从 Cloud Storage 下载文件的代码。您不能只是在 Cloud Storage 中构建文件路径,然后将其传递给其他组件,然后希望它知道如何处理该路径。您所做的只是将不存在的本地文件的名称传递给它。您必须将文件实际下载到临时文件夹才能在本地使用它。

    或者更好的是,只需跳过 Cloud Storage 并将模板与您的函数一起部署即可。您可以直接从磁盘读取文件,无需额外费用。 (每次 Cloud Storage 下载都要花钱。)

    【讨论】:

    • 感谢您对访问 Cloud Storage 中的文件的解释 - 我是 Fb/Storage 的新手,并认为 onCreate 触发器会是更好的选择。当您说“将模板与您的函数一起部署”时,您能澄清一下您指的是 HTTP 函数/快速服务器而不是数据库触发器函数吗?
    • 我的意思是您可以将其他文件连同您的源代码一起部署到 Cloud Functions。这些其他文件将在您运行函数的实例的本地目录中可读。您可以对任何类型的云函数执行此操作。
    • 我最初上传了带有功能的模板,但无法完全正确地获取文件的路径,因此怀疑是否上传了模板。这让我开始考虑使用 Cloud Storage,但遇到了同样的路径问题,而且感觉不正确。结果证明解决方案非常简单。我只需要更改const templatesFolder = __dirname + "/templates"; 并将模板文件夹添加到我的项目的“functions/lib”目录中。
    • 不要使用完整的文件路径。使用相对路径。它的实际位置将植根于您的函数文件夹的内容。
    【解决方案2】:

    这是更新后的函数:

    import * as functions from "firebase-functions";
    const admin = require("firebase-admin");
    const hbs = require("nodemailer-express-handlebars");
    const nodemailer = require("nodemailer");
    
    const smtpConfig = {
      host: "mailHost",
      port: 465,
      secure: true,
      auth: {
        user: "xxxxxxxx",
        pass: "xxxxxxxx"
      }
    };
    
    const transporter = nodemailer.createTransport(smtpConfig);
    
    exports.sendEmail = functions.database
      .ref("/databasePath/{pushId}")
      .onCreate(async (snapshot, context) => {
        const userData = snapshot.val();
        const templatesFolder = __dirname + "/templates"; // <--
    
        transporter.use(
          "compile",
          hbs({
            viewPath: templatesFolder,
            extName: ".handlebars"
          })
        );
        const uniqueCode = "generated by a function";
        const uniqueLink = "https://appId.firebaseapp.com/?id=" + uniqueCode;
        const message = {
          from: "fromEmail",
          to: userData.email, // from the snapshot
          subject: "Subject",
          template: "testTemplate", // name of the template file
          context: {
            user: userDate.name, // from the snapshot
            link: uniqueLink
          }
        };
    
        try {
          await transporter.sendMail(message);
          console.log("Email sent to:", userData.email);
        } catch (error) {
          console.error("Error sending email:", error);
        }
        return null;
      });

    将模板文件添加到“functions/lib/templates/testTemplate.handlebars”

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-13
      • 2019-06-24
      • 1970-01-01
      • 2019-12-19
      相关资源
      最近更新 更多