Как использовать шаблон hbs в Firebase Storage с помощью nodemailer-express-handlebars в функции триггера onCreate базы данных?

Я пытаюсь использовать файл шаблона руля, загруженный в мое хранилище проектов firebase (appId.appspot.com/templates/testTemplate.hbs) с nodemailer, для отправки электронного письма, когда функция 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'в Error (native) errno: -2, code: 'ENOENT', системный вызов: 'open', путь: '/user_code/appId.appspot.com/templates/testTemplate.hbs' }

В начале файла bucket.name указано "/ user_code", поэтому hbs не может найти шаблон. Как я могу получить правильный путь к папке с шаблонами?

2 ответа

Похоже, вы на самом деле не написали код, который загружает файл из облачного хранилища. Вы не можете просто создать путь к файлу в облачном хранилище, передать его другому компоненту и надеяться, что он просто знает, что делать с этим путем. Все, что вы сделали, это передали имя локального файла, который не существует. Вам нужно будет на самом деле загрузить файл во временную папку, чтобы использовать его локально.

Или еще лучше, просто пропустите Cloud Storage и разверните шаблон вместе с вашими функциями. Вы можете просто прочитать файл прямо с диска без каких-либо дополнительных затрат. (Каждая загрузка Cloud Storage стоит денег.)

Вот обновленная функция:

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"