Tips for speeding up the process of sending emails with nodemailer and firebase

We've successfully implemented code that triggers emails to a user and their contacts whenever a new node is added to a specific path in Firebase's realtime database.

Currently, the average time taken to send these emails is approximately 4 minutes. We suspect this delay might be attributed to the need for certain promises to resolve before execution.

We are seeking advice on how we can optimize our code to improve runtime efficiency. Any suggestions would be greatly appreciated. Thank you in advance!

Below is an excerpt of our existing code:

 // Your code snippet goes here...

Additionally, I'd suggest looking into list comprehensions as demonstrated below:

let contacts = contactList.docs
                          .filter((doc) => doc.data().confirmed)
                          .map((doc) => doc.id);

Answer №1

You were almost there, but you forgot to include an await in the main function and also inside the sendMail function for the mailTransport.sendMail call.

This should work correctly:

exports.sendEmails = functions.database.ref("/devices/{device_ID}/history/{alert_ID}")
  .onWrite(
    async (snapshot, context) => { 
      await sendMail(snapshot, context);
      return true;
    }
  );

  async function sendMail(snapshot, context){

    const { before, after } = snapshot;

    // new alert created
    if (before.val() == null) {

      console.log('DEBUG:: NEW ALERT');

      // get owners uID from device ID
      const deviceRef = db.collection('deviceToUid').doc(context.params.device_ID);
      const uidDoc = await deviceRef.get();

      if(!uidDoc.exists){
        functions.logger.info("No such document!");
        return;
      }

      // get users email from uID
      const userRef = db.collection('users').doc(uidDoc.data()[context.params.device_ID]).collection('user-info');

      // get users contact
      const contactRef = db.collection('users').doc(uidDoc.data()[context.params.device_ID]).collection('contacts');

      const [userInfo, contactList] =  await Promise.all([userRef.get(), contactRef.get()]);

      if(userInfo.empty){
        functions.logger.info("No such collection!");
        return;
      }

      const email = userInfo.docs[0].id; // owners email

      let contacts = []; // initialize contact list

      contactList.forEach(
        (doc) => {
          if(doc.data().confirmed){
            contacts.push(doc.id);
          }
        }
      )      

      const mailTransport = nodemailer.createTransport({
        service: 'gmail',
        auth: {
          user: SENDER_EMAIL,
          pass: SENDER_PASSWORD,
        },
      });

      const mailOptions = {
        from: 'ALERT <<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0f61607d6a7f63764f69667d6a6d6e7c6a216c6062">[email protected]</a>>',
        to: email,
        bcc: contacts,
        subject: `...Motion detected`,
        html: `<p dir=ltr>New Alert...</p>`
        
      };

      await mailTransport.sendMail(mailOptions, function (error, info) {
        if (error) {
          console.log(error);
        } else {
          console.log('Email sent: ' + info.response);
        }
      });
      return true;
    }
  }

It's important to use await in the main function to ensure that asynchronous calls are completed before the Cloud Functions container shuts down. More information about this can be found in the documentation on sync, async and promises - and how Cloud Functions are terminated.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The TypeScript error message states that a value of 'undefined' cannot be assigned to a type that expects either a boolean, Connection

I've been grappling with this code snippet for a while now. It was originally written in JavaScript a few months back, but recently I decided to delve into TypeScript. However, I'm struggling to understand how data types are properly defined in T ...

Unlocking the contents of an array from a separate file in Next.js

I am developing a Quiz App that consists of two main pages: takeQuiz.js and result.js. My goal is to transfer the data from the multiple-choice questions (mcqs) in takeQuiz.js to be accessible in result.js. Utilizing router.replace(), I ensure that once th ...

What is the purpose of the Express 4 namespace parameter?

Having worked extensively with Express 4, I recently attempted to implement a namespaced route with a parameter. This would involve routes like: /:username/shows /:username/shows/:showname/episodes I figured this scenario was ideal for express namespacin ...

Is it advisable to incorporate await within Promise.all?

Currently, I am developing express middleware to conduct two asynchronous calls to the database in order to verify whether a username or email is already being used. The functions return promises without a catch block as I aim to keep the database logic se ...

Is it possible for a JWT generated using RS256 to be decoded on the jwt.io platform?

After setting up my first Express server and implementing user authentication with jwt, I'm now searching for a method to encrypt the jwt in order to prevent users from viewing the payload on the website. I am curious if anyone is aware of an encryp ...

Add the file retrieved from Firestore to an array using JavaScript

Trying to push an array retrieved from firestore, but encountering issues where the array appears undefined. Here is the code snippet in question: const temp = []; const reference = firestore.collection("users").doc(user?.uid); firestore .collec ...

Unable to locate the JSON file in the req.body after sending it through an HTTP post request

I have been working on implementing a new feature in my application that involves passing a JSON file from an Angular frontend to a Node backend using Express. The initial code reference can be found at How do I write a JSON object to file via Node server? ...

Every time I attempt to execute this piece of code in "node.js", an error pops up

const express = require('express'); const request = require('request'); const bodyParser = require('body-parser'); const https = require('https'); const app = express(); app.use(express.static('public')); ...

Unable to retrieve an image from various sources

My setup includes an Express server with a designated folder for images. app.use(express.static("files")); When attempting to access an image from the "files" folder at localhost:3000/test, everything functions properly. However, when trying to ...

What steps should I take in order to ensure that NPM commands run smoothly within Eclipse?

I have a functional workflow that I'm looking to enhance. Currently, I am developing a JavaScript library and conducting smoke tests on the code by using webpack to bundle the library and save it to a file that can be included in an HTML file for test ...

Utilizing Think ORM seamlessly across multiple files without the need to repeatedly establish a connection to the

I'm facing a situation where I have numerous models for thinky, and in each file I am required to create a new object for thinky and connect it multiple times due to the high number of models. var dbconfig = require('../config/config.js')[& ...

Building a simple messaging platform with the power of Socket.io and Node.js

After following the guide at http://socket.io/get-started/chat/, I attempted to create a basic chat application. However, upon running npm install --save socket.io I encountered the error message below. How can I resolve this issue? npm WARN package.jso ...

Best Practices for Safely Storing the JWT Client Credentials Grant

Currently, I am working on a NodeJS Express Application that connects to an Auth Server using client credentials grant. After receiving the token from the Auth Server, I use it to access data from an API. I am seeking advice on the most effective way to s ...

Is there a way to automatically redirect the server URL when a file is modified?

I am currently experimenting with a function that is supposed to only display a message in the console without redirecting the actual URL of my server when a file is changed. watcher.add("/home/diegonode/Desktop/ExpressCart-master/routes/2.mk"); watche ...

Good day extract a collection of articles

I am trying to parse out the date and full URL from articles. const cheerio = require('cheerio'); const request = require('request'); const resolveRelative = require('resolve-relative-url'); request('https://www.m ...

I encountered an issue when sending a PATCH request via Hoppscotch where the request body content was returned as 'undefined', although the username and ID were successfully

const express = require("express"); const app = express(); const path = require("path"); let port = 8080; const { v4: uuidv4 } = require('uuid'); app.use(express.urlencoded({extended: true})); app.set("views engine", ...

JavaScript parsing error occurred

Encountering a parsing error in my JavaScript code when deploying Firebase functions. The error mentions an unexpected token, indicating there might be a character out of place. I've been stuck on this issue for weeks now. Any assistance would be grea ...

What is the best way to handle waiting for an API call in JavaScript export?

In my Vue app, I've set up my firestore app initialization code as shown below: if (firebase.apps.length) { firebase.app() } else { firebase.initializeApp(config) } export const Firestore = firebase.firestore() export const Auth = firebase.auth() ...

Getting just the main nodes from Firebase using Angularfire

I'm having trouble figuring out how to print just the parent element names from the structure of my database. The image provided shows the layout, but I can't seem to isolate the parent elements successfully. ...

Thorax.js bower installation issue

After following the instructions in this guide: https://github.com/walmartlabs/thorax-seed/blob/master/README.md, I ran into an unexpected issue on my Windows machine. When running npm start It seems like bower is doing a lot of work (presumably loading ...