Reputation: 116
I am trying to use a handlebars template file uploaded to my firebase project storage (appId.appspot.com/templates/testTemplate.hbs) with nodemailer to send an email when an onCreate function is triggered on a realtime database node.
I can send emails successfully using html formatted string but really need to use a template to add dynamic data into the email.
Here my function:
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;
});
When the function is triggered I get the following error in the logs:
There was an error while sending the email: { Error: ENOENT: no such file or directory, open '/user_code/appId.appspot.com/templates/testTemplate.hbs' at Error (native) errno: -2, code: 'ENOENT', syscall: 'open', path: '/user_code/appId.appspot.com/templates/testTemplate.hbs' }
The bucket.name has '/user_code' at the start so hbs can't find the template. How can I get the right path to the templates folder?
Upvotes: 0
Views: 1187
Reputation: 116
Here's the updated function:
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;
});
Add the template files to "functions/lib/templates/testTemplate.handlebars"
Upvotes: 0
Reputation: 317760
It doesn't look like you haven't actually written any code that downloads a file from Cloud Storage. You can't just build a path to a file in Cloud Storage, pass it off to some other component, and hope it just knows what to do with the path. All you've done is pass it the name of a local file that doesn't exist. You're going to have to actually download the file to a temp folder in order to make use of it locally.
Or better yet, just skip Cloud Storage and deploy the template along with your functions. You can just read the file directly off disk at no additional cost. (Each Cloud Storage download costs money.)
Upvotes: 0