0

I am doing the user email verification in node js using nodemailer my code is below.

// Create new User
const createUser = async function (req, res) {

    // Check if this user already exisits.
    let user = await User.findOne({ email: req.body.email });
    if (user) {
        return res.status(400).send('That user already exists!');
    } else {
        // Insert the new user if they do not exist yet.
        user = new User({
            name: req.body.name,
            email: req.body.email,
            password: req.body.password
        });

        // Hash the password before saving into database.
        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(user.password, salt);
        await user.save();

        // Generating the token for user verification
        const token = new Token({ userId: user._id, token: crypto.randomBytes(16).toString('hex') });
        await token.save();

        // Send varification email
        const link = `${process.env.BASE_URL}/users/confirm/${token.token}`;
        await sendEmail(user.email, "Email Verification\n", link);
        console.log(token)
        res.status(200).send({
            message: "Email Verification link sent to your email",
        });
    }
};

// Verify Email address Api
const confirmationPost = function (req, res, next) {

    // Find a matching token
    Token.findOne({ token: req.params.token }, function (err, token) {
        if (!token) return res.status(400).send({
            type: 'not-verified',
            msg: `We were unable to find a valid token.Your token my have expired.`
        });

        // If we found a token, find a matching user
        User.findOne({ _id: token.userId }, function (err, user) {
            if (!user) return res.status(400).send({ msg: 'We were unable to find a user for this token.' });
            if (user.isVerified) return res.status(400).send({
                type: 'already-verified',
                msg: 'This user has already been verified.'
            });

            // Verify and save the user
            user.isVerified = true;
            user.save(function (err) {
                if (err) { return res.status(500).send({ msg: err.message }); }
                res.status(200).send("The account has been verified. Please login.");
            });
        });
    });
};

// Routes

router.post('/api/users/create', createUser);

router.get('/api/users/confirm/:token', confirmationPost);

// This is sendEmail file

const nodemailer = require('nodemailer');

const sendEmail = async (email, subject, link) => {
    try {
        const transporter = nodemailer.createTransport({
            host: "smtp.mailtrap.io",
            port: 2525,
            auth: {
                user: process.env.USER,
                pass: process.env.PASS,
            },`enter code here`
        });

        await transporter.sendMail({
            from: 'noreply@gmail.com',
            to: email,
            subject: subject,
            text: 'Hello,\n Welcome. Please click on the link to verify your account.\n' +link,
            html: '<a href="${link}">Verify Email.</a>'
        });

    } catch (error) {
        return error;
    }
};

module.exports = sendEmail;

This code worked and I get an email on my mail trap login but when I click on verify email it does not work. The email I got.

Hello, Welcome. Please click on the link to verify your account. http://localhost:5000/api/users/confirm/10da46424f275844cad3a2635e05546d

In the text version of the email, I am getting the correct link but when I click on the verify link it said no URL exists. I think maybe there is some syntax problem with that line can someone guide me?

html: 'Verify Email.'

Calypso
  • 21
  • 3
  • 6

2 Answers2

0

I think this is not an issue with nodemailer, instead you have problem with your URL routing, the URL you are sending with Email is /api/users/confirm/:token, whereas in your application you are handling /confirm/:token which doesn't match the url, hence you are getting URL not found.

Just update your route to /api/users/confirm/:token or /users/confirm/:token (based on your configuration).

Ashok
  • 2,411
  • 1
  • 13
  • 23
  • my complete API route is this http://localhost:5000/api/users/confirm/:token and if I run this route in the browser it tells me email verified but it is not working in the email link. – Calypso Mar 10 '22 at 20:42
  • @Calypso, can you post the screenshot for both error and success? Also, can you check the email content by right clicking on the email and checking the URL there. Since after looking again in the codebase, I think you have an `$` at the start of the URL, but the string is not using string template (i.e. `\``) instead it is using `"`. So your code might become `html: \`Verify Email.\`` instead of `'Verify Email.'` (Note that the single quote has been replaced with ` ) – Ashok Mar 11 '22 at 12:48
0

Its works when you add

return res.redirect("http://localhost:5000")

to the end of your confirmation function.