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}`
})
}