如何在这个控制器函数中包含这个 nodemailer 函数?

How to include this nodemailer function inside this controller function?

我正在尝试创建一个表单,该表单首先将数据发送到 Mongo 数据库,然后通过 Nodemailer 通过电子邮件发送该数据。这是 2 个函数:

控制器功能

exports.createListing = (req, res) => {
    // Validate request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Fields can not be empty"
        });
    }

    const listing = new Listing({
        title: req.body.title, 
        city: req.body.city,
        street: req.body.street,
        businessname: req.body.businessname,
        description: req.body.description
    });

    listing.save()
    .then(data => {
        res.send(data);
    }).catch(err => {
        res.status(500).send({
            message: err.message || "Some error occurred while creating the listing."
        });
    });
};

NodeMailer 函数

 var smtpTransport = nodemailer.createTransport({
        service: 'Gmail',
        port: 465,
        auth: {
          user: 'YOUR_GMAIL_SERVER',
          pass: 'YOUR_GMAIL_PASSWORD'
        }
      });

      var mailOptions = {
        to: data.email,
        subject: 'ENTER_YOUR_SUBJECT',
        html: `<p>${data.title}</p>
              <p>${data.city}</p>
              <p>${data.street}</p>`,
              ...
      };

      smtpTransport.sendMail(mailOptions,
        (error, response) => {
          if (error) {
            res.send(error)
          } else {
            res.send('Success')
          }
          smtpTransport.close();
        });

如何在上面的创建列表函数中包含这个 Nodemailer 部分,以及如何在电子邮件正文中包含提交的数据。我假设当前 data.title 和电子邮件正文中的其他选项是错误的方式。

创建单独的 mail.js 或 anyname.js

var config  = require('../config/config.js');
var nodemailer = require('nodemailer');

var smtpTransport = nodemailer.createTransport({
    service :"gmail",
    host: "smtp.gmail.com",
    auth :
    {
        user: config.email,
        pass: config.password
    }
});


// setup email data with unicode symbols
var mailOptions = {
    from: config.email,
    to: 'user to send',
    subject :'message',
    text :' "Hi",\n You have successfully created an account"',
    html: '<b>Welcome?</b>' // html body
};

// sends mail
module.exports.sendMail  = function()
{
 // send mail with defined transport object
 smtpTransport.sendMail(mailOptions, (error, info) => {
    if (error)
    {
        return console.log(error);
    }
    console.log('Message sent: %s', info.messageId);});
}

现在将此文件导入控制器 js 文件

var mailer = require('./mail.js');

并像下面这样使用它

mailer.sendMail()

您可以在 sendMail 函数中传递值或参数并在 mail.js 文件中访问它们以创建自定义消息或标题或名称

我建议围绕 nodemailer 创建一个包装器模块,因此您可以多次重复使用 sendEmail 函数。

为自己创建一个名为 email-client.js 的文件或任何您想要的文件。在此模块中,您可以在 smtpTransport 上创建一个闭包并仅导出 sendEmail 函数。

电子邮件客户端

const nodemailer = require("nodemailer");

const smtpTransport = nodemailer.createTransport({
    service: "Gmail",
    port: 465,
    auth: {
        user: "YOUR_GMAIL_SERVER",
        pass: "YOUR_GMAIL_PASSWORD"
    }
});

async function sendMail({ to, subject, html }) {
    return smtpTransport.sendMail({ to, subject, html });
}

module.exports = {
    sendMail
};

注意:smtpTransport.sendMail returns 一个 Promise,我们将在您的控制器中处理。

控制器

首先,您可以导入从 email-client.js 导出的 sendEmail 函数,然后您可以在您的控制器中使用它。请注意,我已将控制器更改为 async & prefer mongoose Model.create(使测试更容易一些)。

const { sendEmail } = require("./email-client.js");

exports.createListing = async (req, res) => {
    try {
        if (!req.body.content) {
            return res.status(400).send({
                message: "Fields can not be empty"
            });
        }

        const listing = await Listing.create({
            title: req.body.title,
            city: req.body.city,
            street: req.body.street,
            businessname: req.body.businessname,
            description: req.body.description
        });

        await sendEmail({
            to: "blabla",
            subject: "blabla",
            html: `<p>${listing.title}</p>
        <p>${listing.city}</p>
        <p>${listing.street}</p>`
        });

        return res.send("Success");
    } catch (error) {
        return res.status(500).send({
            message:
                error.message ||
                "Some error occurred while creating the listing."
        });
    }
};

此处最简单的形式是将函数与回调(nodemailer 之一)包装在 Promise 中:

exports.createListing = (req, res) => {
    // Validate request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Fields can not be empty"
        });
    }

    // Set options after the request was verified.

    const smtpTransport = nodemailer.createTransport({
        service: 'Gmail',
        port: 465,
        auth: {
          user: 'YOUR_GMAIL_SERVER',
          pass: 'YOUR_GMAIL_PASSWORD'
        }
    });

    const listing = new Listing({
        title: req.body.title, 
        city: req.body.city,
        street: req.body.street,
        businessname: req.body.businessname,
        description: req.body.description
    });

    listing.save()
    .then(data => new Promise((resolve, reject) => {
      var mailOptions = {
        to: data.email,
        subject: 'ENTER_YOUR_SUBJECT',
        html: `<p>${data.title}</p>
              <p>${data.city}</p>
              <p>${data.street}</p>`,
              ...
      };

      smtpTransport.sendMail(mailOptions,
        (error, response) => {
          if (error) {
            reject(error);
          } else {
            resolve(data);
          }

        });

    })
    .then(data => {
      smtpTransport.close(); // this awaited the actual send
      res.send(data); 
    }
    .catch(err => {
        res.status(500).send({
            message: err.message || "Some error occurred while creating the listing."
        });
    });
};

请注意,这里的 resolve(data) 有效地将结果传递给 Promise 链中的下一个 link,这比在同一范围内嵌套 promise 链只是为了访问要好相同的值。然后,当任一方法失败时,您也有 catch() 的单点。

也就是说,已经引起注意,当前 API 在没有回调的情况下调用时实际上会 return 一个 Promise,但是你可能想要 asyncawait 语法,以便更清晰地访问内容:

exports.createListing = async (req, res) => { // <-- mark block as async
    // Validate request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Fields can not be empty"
        });
    }

    // Set options after the request was verified.

    const smtpTransport = nodemailer.createTransport({
        service: 'Gmail',
        port: 465,
        auth: {
          user: 'YOUR_GMAIL_SERVER',
          pass: 'YOUR_GMAIL_PASSWORD'
        }
    });

    const listing = new Listing({
        title: req.body.title, 
        city: req.body.city,
        street: req.body.street,
        businessname: req.body.businessname,
        description: req.body.description
    });

    try {                                    // try..catch for error handling

      let data = await listing.save();       // await the save

      var mailOptions = {
        to: data.email,
        subject: 'ENTER_YOUR_SUBJECT',
        html: `<p>${data.title}</p>
              <p>${data.city}</p>
              <p>${data.street}</p>`,
              ...
      };

      await smtpTransport.sendMail(mailOptions);   // await the sendMail

      smtpTransport.close(); // this awaited the actual send
      res.send(data); 
    } catch(err) {
      res.status(500).send({
         essage: err.message || "Some error occurred while creating the listing."
    }
};

还需要注意的是,这种方法是串行执行的。因此,除非正确保存数据,否则此处不会发送邮件。这可能是也可能不是您想要的情况,但简单地创建包装 Promise 至少应该遵循正确的方向。

导出您的 sendMail 方法并将其导入您的控制器。

控制器功能

let sendMail = require('your nodemailer file').sendMail;
exports.createListing = (req, res) => {
    // Validate request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Fields can not be empty"
        });
    }

    const listing = new Listing({
        title: req.body.title, 
        city: req.body.city,
        street: req.body.street,
        businessname: req.body.businessname,
        description: req.body.description
    });

    listing.save()
    .then(data => {
        sendMail({
        title: req.body.title, 
        city: req.body.city,
        street: req.body.street})
        res.send(data);
    }).catch(err => {
        res.status(500).send({
            message: err.message || "Some error occurred while creating the listing."
        });
    });
};

NodeMailer 函数

var smtpTransport = nodemailer.createTransport({
        service: 'Gmail',
        port: 465,
        auth: {
          user: 'YOUR_GMAIL_SERVER',
          pass: 'YOUR_GMAIL_PASSWORD'
        }
      });



module.exports.sendmail = (data)=>{
return new Promise((resolve,reject)=>{

      var mailOptions = {
        to: data.email,
        subject: 'ENTER_YOUR_SUBJECT',
        html: `<p>${data.title}</p>
              <p>${data.city}</p>
              <p>${data.street}</p>`,
              ...
      };





      smtpTransport.sendMail(mailOptions,
        (error, response) => {
          if (error) {
            reject(error);
          } else {
            resolve('Success');
          }
          smtpTransport.close();
        });
});
};