Search code examples
javascriptreactjsexpressmongoosemailgun

Getting Mailgun 'ERR_HTTP_HEADERS_SENT'


I have a simple function that returns a status and some JSON. With the form input I am saving user data to the Db and at the same time Sending the email message to that user via mailgun . All working fine but error may occurs into the terminal This is the code for that .

exports.signup = (req, res) => {
  const errors = validationResult(req);

  if (!errors.isEmpty()) {
    return res.status(422).json({
      // error: [errors.array()[0].msg || errors.array()[1].msg],

      errors: [
        {
          msg: errors.array()[0].msg,
          param: errors.array()[0].param,
        },
      ],
    });
  }

  const user = new User(req.body);
  const { email, name } = req.body;
  user.save((err, user) => {
    if (err) {
      return res.status(400).json({
        err: "NOT able to save user in DB",
      });
    } else {
      res.json({
        name: user.name,
        email: user.email,
        id: user._id,
        // password: user.password,
      });
    }

    // mailgun - sending the mail
    const data = {
      from: "[email protected]",
      to: email,
      subject: "sending mail using mailgun",
      text: "Testing some Mailgun awesomness!",
      html: `<h1>Hey ${name} </h1> 
      <h2>Welcome , It's great to have you on board! </h2>`,
    };
    mg.messages().send(data, function (error, body) {
      // console.log("mail send to user successfully");
      if (error) {
        return res.json({
          error: error.message,
        });
      }
      res.json({ message: "Email has been send successfully" });
    });
  });
};

this throws an error:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

_http_outgoing.js:526
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:526:11)
    at ServerResponse.header (C:\Users\Prathamesh\Desktop\College consession system\projBackend\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (C:\Users\Prathamesh\Desktop\College consession system\projBackend\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\Prathamesh\Desktop\College consession system\projBackend\node_modules\express\lib\response.js:267:15)
    at Request.callback (C:\Users\Prathamesh\Desktop\College consession system\projBackend\controllers\auth.js:61:11)
    at IncomingMessage.<anonymous> (C:\Users\Prathamesh\Desktop\College consession system\projBackend\node_modules\mailgun-js\lib\request.js:331:19)
    at IncomingMessage.emit (events.js:323:22)
    at endReadableNT (_stream_readable.js:1204:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21) {
  code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...

Solution

  • This is one of the common mistakes that developers do while sending response to the client.

    And it's an implementation error. It has nothing to do with the Mailgun API

    If you take a closer look at your code, after writing the user data to the database, you are sending the response

    res.json({
            name: user.name,
            email: user.email,
            id: user._id,
            // password: user.password,
          });
    

    And again, once the mail is sent, you are sending the response to the client

    res.json({ message: "Email has been send successfully" });

    If I'm right this must be the issue.

    Possible solution may be, changing your code to something like this :

    exports.signup = async (req, res) => {
      const errors = validationResult(req);
    
      if (!errors.isEmpty()) {
        return res.status(422).json({
          // error: [errors.array()[0].msg || errors.array()[1].msg],
    
          errors: [
            {
              msg: errors.array()[0].msg,
              param: errors.array()[0].param,
            },
          ],
        });
      }
    
      const user = new User(req.body);
      const { email, name } = req.body;
      let userData = "null"
      
       try {
        userData = await user.save();
        } 
       catch(err){
         return res.json({
             error: err.message,
            });
         }
    
        // mailgun - sending the mail
        const data = {
          from: "[email protected]",
          to: email,
          subject: "sending mail using mailgun",
          text: "Testing some Mailgun awesomness!",
          html: `<h1>Hey ${name} </h1> 
          <h2>Welcome , It's great to have you on board! </h2>`,
        };
        mg.messages().send(data, function (error, body) {
          // console.log("mail send to user successfully");
          if (error) {
            return res.json({
              error: error.message,
            });
          }
          return res.json({ message: "Email has been send successfully",...userData });
        });
      });
    };