如何减少电子邮件发送时间(使用 nodemailer 和 firebase)?

How to reduce email sending time (using nodemailer and firebase)?

我们编写了代码,当新节点添加到 Firebase 实时数据库中的特定路径时,会向用户及其联系人发送电子邮件。

发送电子邮件的平均时间为 4 分钟。 我们认为问题是由于等待一些需要的承诺。 我们希望缩短 运行 时间。 你有什么建议吗?提前致谢!

这是我们的代码:

const functions = require("firebase-functions");
const nodemailer = require('nodemailer');
require('dotenv').config()

//for fire store
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

const { SENDER_EMAIL, SENDER_PASSWORD } = process.env;

exports.sendEmails = functions.database.ref("/devices/{device_ID}/history/{alert_ID}")
  .onWrite(
    (snapshot, context) => { 

      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 <noreply@firebase.com>',
        to: email,
        bcc: contacts,
        subject: `...Motion detected`,
        html: `<p dir=ltr>New Alert...</p>`
        
      };

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

我还建议学习一些关于列表理解的知识,如下所示:

  let contacts = []; // initialize contact list

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

可以简化为更简洁的:

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

您已经非常接近了,但是在顶级函数中缺少一个 await,并且在 sendMail 中缺少一个用于调用 mailTransport.sendMail

我觉得应该是这样的:

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 <noreply@firebase.com>',
        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;
    }
  }

由于您未在顶级调用中使用 await,云函数包含 will/may 在异步调用完成之前关闭容器。有关更多信息,请参阅 sync, async and promises - and how Cloud Functions are terminated.

上的文档