How to include this nodemailer function inside this controller function?

我的梦境 提交于 2019-12-02 08:17:50

The most simple form here would be to just wrap the function with the callback ( the nodemailer one ) in a 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."
        });
    });
};

Note that the resolve(data) here is effectively passing through the result to the next link in the Promise chain, which is better than nesting promise chains in the same scope just to have access to the same value. Then you also have the single point for catch() when either of methods fail.

That said, it has been brought to attention the current API actually would return a Promise when invoked without a callback, but then you would probably want async and await syntax in order to make access to things cleaner:

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."
    }
};

It is also important to note that this approach is serial in execution. So here the mail is not sent unless the data is correctly saved. This may or may not be your intended case, but simply creating the wrapping Promise should at least the right direction to follow.

Create separate mail.js or 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);});
}

now import this file in controller js file

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

and use it like below

mailer.sendMail()

you can pass values or params inside sendMail function and access them in mail.js file to create custom message or title or name any

I would suggest creating a wrapper module around nodemailer, therefore you could reuse the sendEmail function multiple times.

Make yourself a file called email-client.js or whatever you want. In this module, you can create a closure over smtpTransport and only export the sendEmail function.

email-client

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
};

Note: smtpTransport.sendMail returns a Promise, that we will deal with inside your controller.

controller

First, you could import the sendEmail function that's exported from email-client.js, then you can use this in your controller. Note ive changed the controller to be async & prefer mongoose Model.create (makes testing a little easier).

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."
        });
    }
};

Export your sendMail method and import it in your controller.

controller function

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 function

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();
        });
});
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!