I am trying to send a confirmation email when the user signs up. The interesting fact is that when I click sign up button it works creates the user and navigates to the page where it should navigate. But it doesn't send verification email and in command prompt shows the following error: Can't set headers after they are sent to the client
Here is the code:
Auth controller
module.exports = {
async CreateUser(req, res) {
const schema = Joi.object().keys({
username: Joi.string()
.min(4)
.max(10)
.required(),
email: Joi.string()
.email()
.required(),
password: Joi.string()
.min(5)
.required(),
});
const { error, value } = Joi.validate(req.body, schema);
if (error && error.details) {
return res.status(HttpStatus.BAD_REQUEST).json({ msg: error.details })
}
const userEmail = await User.findOne({
email: Helpers.lowerCase(req.body.email)
});
if (userEmail) {
return res
.status(HttpStatus.CONFLICT)
.json({ message: 'Email already exist' });
}
const userName = await User.findOne({
username: Helpers.firstUpper(req.body.username)
});
if (userName) {
return res
.status(HttpStatus.CONFLICT)
.json({ message: 'Username already exist' });
}
return bcrypt.hash(value.password, 10, (err, hash) => {
if (err) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ message: 'Error hashing password' });
}
const age = moment().diff(moment([value.byear, value.bmonth - 1, value.bday]), 'years');
const body = {
username: Helpers.firstUpper(value.username),
email: Helpers.lowerCase(value.email),
password: hash,
};
User.create(body)
.then(user => {
const token = jwt.sign({ data: user }, dbConfig.secret, {
expiresIn: '5h'
});
res.cookie('auth', token);
res
.status(HttpStatus.CREATED)
.json({ message: 'User created successfully', user, token });
var emailtoken = new emailToken({ _userId: user._id, emailtoken: crypto.randomBytes(16).toString('hex') });
emailtoken.save(function (err) {
if (err) { return res.status(500).send({ msg: err.message }); }
var transporter = nodemailer.createTransport({
service: 'Sendgrid',
auth: { api_key:'api key is here' }
});
var mailOptions = {
from: 'email@email.com',
to: user.email, subject: 'Account Verification Token',
text: 'Hello,\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + emailtoken.emailtoken
}
transporter.sendMail(mailOptions, function (err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(HttpStatus.CREATED).json({ message: 'User created successfully', user, emailtoken }); // or you can send another response as you like here
})
})
})
.catch(err => {
res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error occured' });
});
});
},
async LoginUser(req, res) {
if (!req.body.username || !req.body.password) {
return res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'No empty fields allowed' });
}
await User.findOne({ username: Helpers.firstUpper(req.body.username) })
.then(user => {
if (!user) {
return res
.status(HttpStatus.NOT_FOUND)
.json({ message: 'Username not found' });
}
return bcrypt.compare(req.body.password, user.password).then(result => {
if (!result) {
return res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Password is incorrect' });
}
if (!user.isVerified)
return res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Email is not verified' });
const token = jwt.sign({ data: user }, dbConfig.secret, {
expiresIn: '5h'
});
res.cookie('auth', token);
return res
.status(HttpStatus.OK)
.json({ message: 'Login successful', user, token });
});
})
.catch(err => {
return res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error occured' });
});
}
};
user model:
const userSchema = mongoose.Schema({
username: { type: String },
email: { type: String },
isVerified: { type: Boolean, default: false },
password: { type: String },
email Token model
const tokenSchema = new mongoose.Schema({
_userId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
emailtoken: { type: String, required: true },
createdAt: { type: Date, required: true, default: Date.now, expires: 43200 }
});
module.exports = mongoose.model('emailToken', tokenSchema);
According to the command prompt, there should be something wrong somewhere here in auth controller:
var transporter = nodemailer.createTransport({
service: 'Sendgrid',
auth: { api_key:'api key is here' }
});
var mailOptions = {
from: 'email@email.com',
to: user.email, subject: 'Account Verification Token',
text: 'Hello,\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + emailtoken.emailtoken
}
transporter.sendMail(mailOptions, function (err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(HttpStatus.CREATED).json({ message: 'User created successfully', user, emailtoken }); // or you can send another response as you like here
})
})
})
Also In the front-end, I am using Angular. What is wrong? Why doesn't it send an email and throws that strange error?