2
votes

I have setup a firebase-function with nodemailer to grab the input from my firebase-database connected to my contact form and email it to my email.

I have successfully deployed the function and can see the function showing up in my firebase console, however i do not receive any errors in the console nor see any logs or information in the function section of the console. And it just simply doesn't work right now.

This is the first time i am doing this, and i have looked at almost all other similar questions on SO but none of them have given me any clues as to what i am doing wrong.

This is my functions package.json:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "8"
  },
  "dependencies": {
    "firebase-admin": "~7.0.0",
    "firebase-functions": "^2.3.0",
    "nodemailer": "^6.1.1"
  },
  "devDependencies": {
    "eslint-plugin-promise": "^4.0.1",
    "firebase-functions-test": "^0.1.6"
  },
  "private": true
}

and this is the index.js code inside the functions-folder:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");


const gmailEmail = "k****[email protected]";
const gmailPassword = functions.config().gmail.pass;

admin.initializeApp();


var goMail = function(message) {

  const transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
      user: gmailEmail,
      pass: gmailPassword
    }
  });


  const mailOptions = {
    from: gmailEmail, // sender address
    to: "****[email protected]", // list of receivers
    subject: "!", // Subject line
    text: "!" + message, // plain text body
    html: "!" + message // html body
  };


  const getDeliveryStatus = function(error, info) {
    if (error) {
      return console.log(error);
    }
    console.log("Message sent: %s", info.messageId);

  };


  transporter.sendMail(mailOptions, getDeliveryStatus);
};

exports.onDataAdded = functions.database
  .ref("/messages/{messageId}")
  .onCreate(function(snap, context) {

    const createdData = snap.val();
    var name = createdData.name;
    var email = createdData.email;
    var number = createdData.number;
    var message = createdData.message;


    goMail(name, email, number, message);
  });

I'm not sure if my setup is wrong or if I'm doing something wrong with the nodemailer code in index.js.

Thanks for the help in advance.

1
How do you trigger the function?Frank van Puffelen
Really good question Frank, sorry to be such a noob but i am not so sure if i have performed the trigger, i was just looking at another example of doing this from the firebase team on github and did see a section about how they triggered the function based on the changes in the database, but in my own case i am somewhat lost. Would you be kind enough to point me in the right direction? Thank you.-----My database collects 4 different inputs in each collection that has a reference of "messages"Ikai Yanasaki
It sounds like you're pretty new to Cloud Functions, in which case taking a complex sample like the one you found and trying to make it work is probably a bit too much to do at once. The onDataAdded function triggers when a node node is created under /emails, and expects that new node to have an email property that is the message body you want to send to people.Frank van Puffelen
In addition to Frank's recommendations, I would add that since your Cloud Function is triggered by a background event you must return a promise to indicate that the asynchronous tasks are finished. In your case it means that you should return the promise returned by transporter.sendMail() (Node Mailer will return a promise if no callback is given (nodemailer.com/usage)). Returning a promise is key, as explained in the 3 videos about "JavaScript Promises" from the Firebase video series: firebase.google.com/docs/functions/video-seriesRenaud Tarnec
Good catch Renaud!Frank van Puffelen

1 Answers

5
votes

As explained in the comment, since your Cloud Function is triggered by a background event, you must return a promise to indicate that the asynchronous tasks are finished.

So in the goMail function you should return the promise returned by the sendMail() method with:

...
return transporter.sendMail(mailOptions);   //Remove the callback

And you should return, in the Cloud Function itself, the promise returned by the goMail function with:

return goMail(...)