I was trying to set up a email verification method using nodemailer but it seems to not work for some reason. Can anyone find a fix ? i will first generate the token and then send it to the user for them to verify their email and continue login process. I seem to be stuck in this part. Node mailer not sending the email but user registration info does save in the database.
my register route -
const User = require('../models/User');
const router = require('express').Router();
const bcrypt = require('bcrypt');
const mongoose = require('mongoose');
const nodemailer = require('nodemailer');
const Token = require('../models/token');
router.post('/register', async (req,res) => {
try {
user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
// create and save user
await user.save(function(err) {
if (err) {
return res.status(500).send({msg: err.message});
}
});
// genereate token and save
let token = new Token({_userId: user._id, token: crypto.getRandomValues(16).toString('hex')});
token.save(() => {
if(err) {
return res.status(500).send({msg: err.message});
}
let transporter = nodemailer.createTransport({service: 'gmail', auth: {user: 'myEmail', pass: "Password"}});
let mailOptions = {from: "[email protected]", to: user.email, subject: "Account Verification Link"}
transporter.sendMail(mailOptions, function(err) {
if(err) {
return res.status(500).send({msg: "Technical Issue"})
}
return res.status(200).send('Email Sent')
})
});
} catch {
console.log("NO result")
}
});
module.exports = router;
tokenSchema -
const mongoose = require("mongoose");
const tokenSchema = new mongoose.Schema({
_userId: {type: mongoose.Schema.Types.ObjectId, required: true, ref: "user"},
token: {type: String, required: true},
expiredAt: {type: Date, default: Date.now(), index: {expires: 86400000}}
});
const token = mongoose.model('token', tokenSchema);
module.exports = token;
userSchema -
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String, required: true, minlength: 5,maxlength:30
},
email: {
type: String, unique:true, maxlength:30
},
password: {
type: String, minlength: 8, required:true
},
isAdmin: {
type: Boolean, default: false
},
createdAt: {
type: Date, default: Date.now
},
verified: {
type: Boolean, default: false
}
});
app.js -
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const path = require('path');
const authRoute = require('./routes/auth');
dotenv.config();
const app = express();
app.use(express.json());
app.use('/auth', authRoute);
mongoose.connect(process.env.MONGO).then(() => {
console.log('Database Connected')
});
const PORT = process.env.PORT || 5000;
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
app.listen(PORT, () => {
console.log(`Server Online at ${PORT}`);
});
module.exports = mongoose.model('Users', userSchema);
CodePudding user response:
I think it doesn't work because transporter.sendMail()
is asynchronous function you have to use async await
to execute that function.
Try this
token.save(async () => {
if(err) {
return res.status(500).send({msg: err.message});
}
let transporter = nodemailer.createTransport({service: 'gmail', auth: {user: 'myEmail', pass: "Password"}});
let mailOptions = {from: "[email protected]", to: user.email, subject: "Account Verification Link"}
await transporter.sendMail(mailOptions, function(err) {
if(err) {
return res.status(500).send({msg: "Technical Issue"})
}
return res.status(200).send('Email Sent')
})
});
CodePudding user response:
Dharmik Patel's answer problematic
Either you use async/await to run synchronous code, or you use a callbak or promise for asynchronous code.
But not both at the same time.
Here is an example with callback :
mailer.transport.sendMail( mail_config, function( error ) {
if ( error ) {
console.info( 'Mail not sent : ', error );
return;
}
console.info( 'Mail sent ! ');
message.transport.close();
});
Just add console for printing error of mailler callback to see what is the problem.
In general, use promises or calbacks instead to keep the asynchronous advantage of node.js.
Synchronous operation must be reserved for processing that cannot be done asynchronously.