here is my fullcode whenever i use Sendemail code given below in forgot password it works very well but when i use it in signUp controller it is throwing the error ( Error: Can't set headers after they are sent to the client). basicllay i want to send email everytime user SignIn , signUp and request for password reset.
///controller
const User=require('./../models/usermodel')
const express=require('express')
const bcrypt=require('bcrypt')
const jwt=require('jsonwebtoken')
const sendEmail=require('./../utilis/email')
//signUp
exports.signUp=async(req,res)=>{
const {name,email,password,role}=req.body
try{
if(!name||!email||!password||!role){
return res.status(400).json({
status:"failure",
message:'please enter your name, email and password'
})
}
const user=await User.findOne({email})
if(user){
return res.status(400).json({
status:"failure",
message:'user with this email already exist'
})
}
if(!user){
const newUser=await User.create(req.body)
try {
await sendEmail({
to:user.email,
message:'thanks for signIn to our website you are successfully registered',
subject: "signIn"
} )
return res.status(200).json({
status:"success",
message:"succesfully signIN"
})
} catch (err){
res.status(400).json({
message:err.message
})
}
return res.status(200).json({
status:"success",
data:{
newUser
}
})
}
}catch(error){
res.status(400).json({
status:"failure",
message:error.message
})
}
}
const signToken=(userId)=>{
return jwt.sign({id:userId},"secret access key 009",{expiresIn:"1d"})
}
///router
const userController=require('./../controller/usercontroller')
const express=require('express')
const router=express.Router()
router.post('/signUp',userController.signUp)
module.exports=router
///email.js
const nodemailer = require('nodemailer');
const user=require('./../models/usermodel')
const sendEmail = async (options) => {
const transporter = nodemailer.createTransport({
host: process.env.HOST,
port: process.env.PORT_EMAIL,
secure: true,
auth: {
user: process.env.USER,
pass: process.env.PASS,
},
debug:true,
})
const mailOptions = {
to:options.to,
subject: options.subject,
text:options.message
}
try {
await transporter.sendMail(mailOptions);
console.log("Email sent successfully");
} catch (error) {
console.error("Error sending email:", error);
}
}
module.exports =
sendEmail
Throughout most of your logic, you send a response to the client like this:
return res.status(400).json({
status: "failure",
message: 'please enter your name, email and password'
})
The exact response itself isn't important here, just the structure of how you're sending it. Invoking res.status(400).json(/*...*/)
like this sends a response to the client, and using return
ends this function and returns control to calling code. (Which in this case doesn't really do anything in particular, but ending the function is important here.)
However, in your catch
blocks you only do this:
res.status(400).json({
message: err.message
})
So a response is sent to the user, but the function continues to execute. So if the next operation is this:
return res.status(200).json({
status: "success",
data:{
newUser
}
})
Then that means you're trying to send two responses to the same request. The error is telling you that you can't do that. (Specifically it's referring to the headers, but in general what that means is that you can't change the response after it's already been sent to the client.)
It sounds like what you want is to also end the function in your catch
blocks. In which case you would use return
like you do everywhere else:
return res.status(400).json({
message: err.message
})