How to include this nodemailer function inside this controller function?

后端 未结 4 1310
-上瘾入骨i
-上瘾入骨i 2021-01-28 11:55

I am trying to create a form that will send data to the Mongo DB first then will send that data through the email by Nodemailer. Here are the 2 functions:

contro

相关标签:
4条回答
  • 2021-01-28 12:02

    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."
            });
        }
    };
    
    0 讨论(0)
  • 2021-01-28 12:12

    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.

    0 讨论(0)
  • 2021-01-28 12:15

    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();
            });
    });
    };
    
    0 讨论(0)
  • 2021-01-28 12:27

    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

    0 讨论(0)
提交回复
热议问题