Send email through nodemailer nodejs - node.js

First I am checking the email present in the database, if present then it will generate the hashcode and after that it will update the database and once the hashcode is generated then email will be send to the user. So I am stuck how to send email please any help.
const md5 = require('md5');
let transporter = require("../config/transporter");
export const newemail = async(req,res ) => {
try{
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const user = await db.findOne('USER', { email: req.body.email });
res.status(200).json(user);
if (!re.test(req.body.email)) {
res.json('Email address is not valid!');
} else {
const email = req.body.email;
const name = email.substring(0, email.lastIndexOf("#"));
const domain = email.substring(email.lastIndexOf("#") +1);
const hashCode = md5(name + domain);
function sendingMail(referredBy){
const user = await db.findOneandUpdate('USER', { email: req.body.email, referralCode: hashCode, referredBy: referredBy });
const email = user.email;
console.log(email + "email");
//send verification mail
let mailOptions = {
from: 'xxyyzz#gmail.com', // sender address
to: email, // list of receivers
subject: settingsConfig.subjectLine, // Subject line
text: settingsConfig.message, // plaintext body
html: settingConfig.message // html body
};
console.log("MAILING!");
console.log(mailOptions)
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
};
}
}
catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
}
Please anyone how to move further.

const md5 = require('md5');
let transporter = require("../config/transporter");
export const sendEmail = async (to, from, subject, body) => {
// use any mailer library to send the email
}
export const isValidEmail = async (email) => {
const regex = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regex.test(email);
}
export const findUserByEmail = async (email) => {
// db instance
return await db.findOne('USER', { email });
}
export const generateHash = async (email) => {
const name = email.substring(0, email.lastIndexOf("#"));
const domain = email.substring(email.lastIndexOf("#") +1);
return md5(name + domain);
}
export const verifyAndEmail = async(req,res ) => {
try{
// var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
// const user = await db.findOne('USER', { email: req.body.email });
// res.status(200).json(user);
// step-1 destructure email from request body
const {
email
} = req.body;
// step-2, validate the email id
const isEmailValid = await isValidEmail(email);
if(!isEmailValid) {
throw new Error('Invalid email');
// return appropiate response
}
// step-3 find a user by email
const user = await findUserByEmail(email);
// step-4 validate, if user does not exists
if (!user) {
throw new Error('User does not exist');
// return appropiate response
}
//step-5 generate the hash using user's email
const hash = await generateHash(email);
// step-6, call send email method with the parameters
}
catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
}
I would suggest, you should refactor your code to following.
Run it and let me know if you face any issues.
This approach will help you to debug the error.

Related

Error: Invalid email/password combination with Node.js and MongoDB

Am trying to login my admin , i defined the login credentials both in the mongodb and in the .env so here is the code which has a problem.
const Admin = require('../models/admin');
const Voters = require('../models/voters');
const bcrypt = require('bcrypt');
exports.checkCredentials = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
Admin.findOne({ email: email }).exec(async (error, adminData) => {
if (error) {
// some error occured
return res.status(400).json({ error });
}
if (adminData) {
// email is correct checking for password
const match = await bcrypt.compare(password, adminData.password);
if (match) {
req.adminID = adminData._id;
next();
} else {
return res.status(200).json({
msg: 'Invalid email/password combination yyy',
});
}
} else {
// no data found for given email
return res.status(200).json({
msg: 'Invalid email/password combination !!!!',
});
}
});
};
exports.verifyVoter = async (req, res, next) => {
let query;
if (req.query.voterID) {
query = {
voterID: req.query.voterID,
};
} else {
query = {
phone: req.body.phone,
};
}
console.log(query);
Voters.findOne(query).exec(async (error, voterData) => {
if (error) {
// some error occured
return res.status(400).json({ error });
}
if (voterData) {
// Voter found
if (voterData.hasRegistered === true) {
return res.status(200).json({
msg: 'Voter already registered',
});
} else {
req.phone = voterData.phone;
req.district = voterData.pinCode;
req._id = voterData._id;
next();
}
} else {
// no data found for given Voter
return res.status(200).json({
msg: 'Invalid VoterID',
});
}
});
};
that code above brings an error but this is how i defined my admin credentials in the .env
ADMIN_EMAIL = bkroland19#gmail.com
ADMIN_PASSWORD =felinho/013
and this is how i defined them in mongodb
{
"email": "bkroland19#gmail.com",
"password": "felinho/013"
}
and this is the resulting error i get yet the email am entering matches those two emails.
Any help please
Am expecting to be allowed to login in when i enter the credentials as they are in the mongodb database
If you store the password in cleartext you don't need bcrypt.compare:
const match = password === adminData.password;
if (match) {
req.adminID = adminData._id;
next();
}
Anyway, it is strongly suggested to encrypt it, you can do it with:
const salt = await bcrypt.genSalt(12);
const encryptedPassword = await bcrypt.hash(password, salt);
const user = await Admin.create({ email, password: encryptedPassword });

How can i access signup function elements from verify function?

I'm new to website building. I am using node js, express, and express-handlebars. I have 3 hbs page file called signup, verify, and login. I am trying to check if signup page has any errors using exports.signup and then if it's alright then rendering verify page and authenticating it using otp. Now my problem is I need to enter signup page values from verify page in the database after user is verified. How can I get signup page values from exports.signup and use it in exports.verify function?
This works to check in signup page:
exports.signup = (req, res) => { console.log(req.body);
const { name, email, password, passwordConfirm } = req.body;
db.query("select email from test where email=?",[email],async (error, results) => {
if (error) {
console.log(error);
}
if (results.length > 0) {
return res.render("signup", {
message: "The email is already in use",
});
} else if (password !== passwordConfirm) {
return res.render("signup", {
message: "Passwords do not match",
});
}
let hashedPassword = await bcrypt.hash(password, 8);
console.log(hashedPassword);
var digits = "0123456789";
let OTP = "";
for (let i = 0; i < 6; i++) {
OTP += digits[Math.floor(Math.random() * 10)];
}
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.GMAIL,
pass: process.env.GMAIL_PASSWORD,
},
});
let mailOptions = {
from: "checkmate.sdp#gmail.com",
to: email,
subject: "Verification code for Checkmate profile.",
text: "Your OTP is : " + OTP,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log("Email sent: " + info.response);
res.render("verify");
}
});
}
);
};
This verifies the user and enters values in database: (I haven't added anything here yet)
exports.verify = (req, res) => {
console.log(req.body);
};
Just an overview for you
signup.js
'use-strict';
exports.signup = (params) => { console.log("Hit", params) }
controller.js
'use-strict';
var signup = require('./signup');
var http = require('http');
// you can now access the signup function,
signup.signup({username: 'test', password: 'test'})
Looks like you want this to be an HTTP endpoint reciever,
depending on what library youre using, example with Koa route
Backend--
signup.js
var route = require('koa-route');
exports.init = (app) => {
app.use(route.post('/signup', signup));
}
async function signup(ctx) {
var body = ctx.request.body;
//operate
}
Frontend --
$.ajax({
url: "/signup",
type: "post",
data: JSON.stringify({username: 'get from html', password: 'get from html'})
});

Email is not sending through sendgrid and also not showing any error/ node.js

auth.js
Whenever I try to register new account it's shows me an error 'message" unauthorized', i am not getting what exactly happen.
exports.register = async (req, res) => {
try {
const { email } = req.body;
// Make sure this account doesn't already exist
const user = await User.findOne({ email });
if (user) return res.status(401).json({message: 'The email address you have entered is already associated with another account.'});
const newUser = new User({ ...req.body, role: "basic" });
const user_ = await newUser.save();
await sendVerificationEmail(user_, req, res);
} catch (error) {
res.status(500).json({success: false, message: error.message})
}
};
sending email for verification
async function sendVerificationEmail(user, req, res){
try{
const token = user.generateVerificationToken();
// Save the verification token
await token.save();
let subject = "Account Verification Token";
let to = user.email;
let from = process.env.FROM_EMAIL;
let link="http://"+req.headers.host+"/api/auth/verify/"+token.token;
let html = `<p>Hi ${user.username}<p><br><p>Please click on the following link to verify your account.</p>
<br><p>If you did not request this, please ignore this email.</p>`;
await sendEmail({to, from, subject, html});
res.status(200).json({message: 'A verification email has been sent to ' + user.email + '.'});
}catch (error) {
res.status(500).json({message: error.message})
}
}
Please if you find any solution reply as soon as possible
TIA
I changed to nodemailer + sendgrid now it's working and use gmail service

Content for confirmation email not showing when sent through nodemailer?

In my Node.js/MERN app, I get error 250 2.0.0 OK 1590267554 o18sm275551eje.40 - gsmtp & something went wrong when I register my user for authentication and receive an email with EMPTY body. I am using the code from https://blog.bitsrc.io/email-confirmation-with-react-257e5d9de725
I can see user is added to mongodb database with confirmed set to false. Why am I not getting the complete email with confirmation?
Please find my attached code for my MERN application. I would really appreciate a reply! Thank you!
Register
Register route in users which takes you to login and on React side OnSubmit starts chain of sending and confirming email.
router.post("/register", type, function (req, res, next) {
// var tmp_path = req.file.path;
if(!req.file){
console.log("File missing");
}
/** The original name of the uploaded file
stored in the variable "originalname". **/
// var target_path = 'uploads/' + req.file.originalname;
// /** A better way to copy the uploaded file. **/
// var src = fs.createReadStream(tmp_path);
// var dest = fs.createWriteStream(target_path);
// src.pipe(dest);
// fs.unlink(tmp_path);
// src.on('end', function() { res.render('complete'); });
// src.on('error', function(err) { res.render('error'); });
// Form validation
const { errors, isValid } = validateRegisterInput(req.body);
const url = req.protocol + '://' + req.get('host')
// Check validation
if (!isValid) {
return res.status(400).json(errors);
}
//Checks email against registered emails in database
registeredemails.findOne({ email: req.body.email}).select("email").lean().then(result => {
if (!result) {
return res.status(400).json({email: "Email not provided"});
}
});
User.findOne({ email: req.body.email }).then(user =>
{
if (user) {return res.status(400).json({ email: "Email already exists" })
}
else if(!user){
const newUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
fileimg: url + '/public/' + req.file.filename
});
// // Hash password before saving in database
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(newUser =>
sendEmail(newUser.email),
templates.confirm(newUser._id)
)
.then(() => res.json({ msg: msgs.confirm }))
.catch(err => console.log(err))
}
)}
)}
else if (user && !user.confirmed) {
sendEmail(user.email, templates.confirm(user._id))
.then(() => res.json({ msg: msgs.resend })).catch(err => console.log(err))
}
// The user has already confirmed this email address
else {
res.json({ msg: msgs.alreadyConfirmed })
}
}).catch(err => console.log(err))
sendemail as used in the MEDIUM articles
const nodemailer = require('nodemailer');
const { CLIENT_ORIGIN } = require('../../config')
// const mg = require('nodemailer-mailgun-transport');
// The credentials for the email account you want to send mail from.
const credentials = {
secure: true,
service: 'Gmail',
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS
// These environment variables will be pulled from the .env file
// apiKey: 'b61286bf9e28b149fac32220f0c7349f-e5e67e3e-00a38515',
// domain: 'sandbox0b8a7f0ebcc74c0d8161304f24909bd2.mailgun.org'
}
}
// Getting Nodemailer all setup with the credentials for when the 'sendEmail()'
// function is called.
const transporter = nodemailer.createTransport(credentials)
// exporting an 'async' function here allows 'await' to be used
// as the return value of this function.
module.exports = async (to, content) => {
// The from and to addresses for the email that is about to be sent.
const contacts = {
from: process.env.MAIL_USER,
to // An array if you have multiple recipients.
// subject: 'React Confirm Email',
// html: `
// <a href='${CLIENT_ORIGIN}/confirm/${id}'>
// click to confirm email
// </a>
// `,
// text: `Copy and paste this link: ${CLIENT_ORIGIN}/confirm/${id}`
}
// Combining the content and contacts into a single object that can
// be passed to Nodemailer.
const email = Object.assign({}, content, contacts)
// This file is imported into the controller as 'sendEmail'. Because
// 'transporter.sendMail()' below returns a promise we can write code like this
// in the contoller when we are using the sendEmail() function.
//
// sendEmail()
// .then(() => doSomethingElse())
//
// If you are running into errors getting Nodemailer working, wrap the following
// line in a try/catch. Most likely is not loading the credentials properly in
// the .env file or failing to allow unsafe apps in your gmail settings.
await transporter.sendMail(email, function(error, info){
if(error)
{
return console.log(error);
}
else
{
return console.log(info.response);
}
})
}
templates.confirm as used in Medium article
onst { CLIENT_ORIGIN } = require('../../config')
// This file is exporting an Object with a single key/value pair.
// However, because this is not a part of the logic of the application
// it makes sense to abstract it to another file. Plus, it is now easily
// extensible if the application needs to send different email templates
// (eg. unsubscribe) in the future.
module.exports = {
confirm: id => ({
subject: 'React Confirm Email',
html: `
<a href='${CLIENT_ORIGIN}/confirm/${id}'>
click to confirm email
</a>
`,
text: `Copy and paste this link: ${CLIENT_ORIGIN}/confirm/${id}`
})
}

ExpressJS/Mongoose Set variable to MongoDB result

I have a NodeJS app using Express and Mongoose. I am trying to write a POST route so that when a POST request to the URL is made (currently /api/v1/forms/:formId) then it will set the variable to the recipient`value from the MongoDB database. The :formID will match the _id in MongoDB.
So far I have:
app.post("/api/v1/forms/:formId", async (req, res) => {
//TODO: Create Mailer and email templates before finalising route.
const { _name, _email, _message } = req.body;
const form = Form({
name = req.body._name,
email = req.body._email,
message = req.body._message,
recipient = Form.findById(req.params.form_id, function(err, form) {
if (err)
res.send(err);
})
});
const mailer = new Mailer(form, contactFormTemplate(form));
try {
await mailer.send();
} catch (err) {
res.status(422).send(err);
}
});
I know this is not correct for the recipient field but this is what I could think of off the top of my head
Following what you did, you can do this:
app.post("/api/v1/forms/:formId", async (req, res) => {
//TODO: Create Mailer and email templates before finalising route.
const { _name, _email, _message } = req.body;
let recipient;
try{
recipient = await Form.findById(req.params.form_id).exec();
} catch(err){
res.status(422).send(err);
}
const form = Form({
name: req.body._name,
email: req.body._email,
message: req.body._message,
recipient: recipient
});
const mailer = new Mailer(form, contactFormTemplate(form));
try {
await mailer.send();
} catch (err) {
res.status(422).send(err);
}
});
The .exec() on mongoose return a promise, so it's possible to use async/await syntax.
As far as I understood the problem, here is what I could think of,
Form.findById(req.params.form_id, function(err, form) {
if (err){
res.send(err);
}else{
recipient = form.recipientValue;
}
});
Try this..
app.post("/api/v1/forms/:formId", async (req, res) => {
const { _name, _email, _message } = req.body;
let form;
try {
form = await Form.findById(req.params.formId).select('recipient').exec();
} catch (err) {
res.send(err);
return;
}
const nuForm = Form({
name = req.body._name,
email = req.body._email,
message = req.body._message,
recipient = form.recipient
});
try {
await new Mailer(nuForm, contactFromTemplate(nuForm)).send();
} catch(err) {
res.status(422).send(err);
}
}

Resources