Show progress while sending multiple emails - javascript

I'm sending multiple emails from my node.js server and I want to show progress on frontend about how many mails have been sent.
I wrote code that sending response only after every email has been sent however i need notify frontend about progress.
As far as I know i cannot send multiple responses on single http request so i kinda lost here.
My emailsend request handler:
const send = async (req, res) => {
//parsing request body
const {user, recievers, subject, text} = req.body;
//Getting sender credentials from db
const user = await UserSettings.findOne({ user }, 'MAIL');
//creating nodemailer transporter
const transporter = nodemailer.createTransport({
service: user.MAIL.SERVICE,
auth: {
user: user.MAIL.USER,
pass: user.MAIL.PASSWORD,
},
});
//sending email to every reciever
recievers.forEach(reciever=> {
const mailOptions = {
from: user.MAIL.USER,
to: reciever,
subject,
text
};
return transporter.sendMail(mailOptions, (error, info) => {
if (!error) {
console.log(`Email sent: ${info.response}`);
} else {
console.log(error);
}
});
});
return res.sendStatus(204);
};

Related

Is it possible to decrypt a password without having to use compare? (bcrypt)

I'm implementing a "forgot password" system in my authentication API in node. For this I created a "forgetPassword" controller where I send the user's email through req.body and with that an email with the recovery token is sent to the user, and that same token is also sent inside of the model user in the database in "tokenReset". The second controller is "resetPassword", where this recovery token is sent by params and a new password is sent in the req.body.
The biggest problem is, I think it's not safe for this token to be in the database without being encrypted, as someone inside the database can take advantage of this as a flaw, so I encrypted the token before sending it to the database. But the big question is, I have to fetch this token inside the database in "resetPassword" controller through the token sent in the params, but the token inside my database is encrypted and the one in the params is not. What would be the best way to resolve this?
forgotPassword controller
const jwt = require('jsonwebtoken');
const db = require('../../models/index');
const sendEmail = require('../../utils/mailer');
const bcrypt = require('bcryptjs');
exports.store = async (req, res) => {
const { email } = req.body;
const secret = process.env.JWT_SECRET;
try {
const user = await db.User.findOne({ where: { email } });
if (!user) {
res.status(400).json('User does not exist.');
}
const token = jwt.sign({ id: user.id }, secret, {
expiresIn: process.env.EXPIRES_FORGOTPASS,
});
const hashedToken = bcrypt.hashSync(token, 10);
await user.update({
tokenReset: hashedToken,
});
sendEmail({
from: 'noreply#email.com',
to: 'admin#gmail.com',
subject: 'Reset your password',
text: `Token sending email to reset password account from ${user.email}`,
html: `<h2>Token sending email to reset password account from ${user.email}</h2>
<h4>${token}</h4>
`,
});
return res.status(200).json('Check the verification link in your email!');
} catch (err) {
return console.log(err);
}
}
resetPassword controller
const jwt = require('jsonwebtoken');
const db = require('../../models/index');
const bcrypt = require('bcryptjs');
const sendEmail = require('../../utils/mailer');
exports.store = async (req, res) => {
const { token } = req.params;
const { password } = req.body;
const secret = process.env.JWT_SECRET;
try {
const userExists = await db.User.findOne({ where: { tokenReset: token } });
if (!userExists) {
return res.status(401).json('User not found in our database!');
}
try {
await jwt.verify(token, secret);
} catch (err) {
return res.status(401).json('Link expired, make a new password reset request!');
}
const hashedNewPass = bcrypt.hashSync(password, 10);
await userExists.update({
password: hashedNewPass,
tokenReset: "",
});
return res.status(200).json(`Password updated!`);
} catch (err) {
return console.log(err);
}
}

Rest API, take request fields. handle

I stood in a stupor. And I need help.
I do rest full api on express
I want to do this if a request comes in type: reset_password -> I sent an email to reset my password.(it can be both registration and auth)
But I don't know how to pass it into a query. And that is, how to do it.
I trimmed the code.
const send = async (req, res) => {
const key = req.query.apiKey;
const type = req.query.type;
const to = req.query.to;
if (err) {
console.log(err);
} else if (rows.length == 0) {
res.status(401).json({"apiKey":"error"})
} else {
if (email.validate(to)) {
sendmail(type, to)
} else {
res.status(422)
}
}
}
sendmail:
const nodemailer = require("nodemailer");
const ejs = require('ejs')
const path = require('path')
const sendmail = async (type, to, url) => {
try {
const reset_password = path.join(__dirname, "../template/resetpassword.ejs")
const signup_auth = path.join(__dirname, "../template/signupauth.ejs")
const sign_in_auth = path.join(__dirname, "../template/signinauth.ejs")
const data = await ejs.renderFile(reset_password,signup_auth,sign_in_auth, { to, url } )
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass, // generated ethereal password
},
});
const send = await transporter.sendMail({
from: 'dev#test.io',
to: to,
text: "Hello world?",
subject: "test",
html: ???
})
console.log("Success send: %s", nodemailer.getTestMessageUrl(send));
}catch (err) {
console.log('Error send: ' + err.message);
}
}
module.exports = sendmail;
Now I have a question. How do I send a request: reset_password,signup_auth,sign_in_auth
That is, how do I pass it on to the type: reset_password,signup_auth,sign_in_auth
http://localhost:3000/api?apiKey=key&type=reset_password,signup_auth,sign_in_auth
How do I take it and process it?
I need to accept type=auth signup reset to api rest
I'm sorry, maybe I didn't make my point correctly.

Unable to Pass Data to Backend from Input

I have an API which will send an email to a user based off the input. This is the on lick submit. I can confirm the data is being console.log for the state.
const inviteUser = async () => {
userRequest.get(`companyprofile/companyUser/invite/${companyuser._id}`, teamMemberEmail);
console.log('invite sent to', (teamMemberEmail))
}
With this api, i send the body to the API and then email based off the text, however when i log the field it does not appear at all and only shows as {}
router.get("/companyUser/invite/:id", async (req, res) => {
// must update to company
var stringLength = 25;
const companyUser = await CompanyProfile.findById(req.params.id)
const companyUserToken = await companyUser.inviteToken
const companyAccessTokenStripped = await companyUserToken.substring(0, stringLength);
//encrypt the accesstoken to invite users
const url = `http://localhost:5000/api/auth/inviteToJoinTeam/${companyUserToken}/${req.body.email}`;
// const url = `http://localhost:5000/api/companyprofile/companyUser/inviteToJoinTeam/${companyUserToken}`;
console.log(req.body)
const mailOptions = {
from: 'company#gmail.com',
to: req.body.email,
subject: `You have been invited to join ${companyUser.CompanyTitle}`,
html: `${companyUser.companyTitle} has invited you to join their team ${url}`
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
try {
// const savedCompany = await newCompany.save();
res.status(201).json(companyUserToken);
} catch (err) {
res.status(500).json(err);
}
});
Can anyone see why i cannot pass this data and email the user? Appears to be an error with how it's passed but i can confirm that the endpoint works in postman if i just plug an email body in
You are trying to send an email whenever the GET route is called. However, the data won't be sent inside as "req.body" as a GET request doesn't have a body.
If you are using GET method then the data is sent as query parameters.
router.get("/companyUser/invite/:email", async (req, res, next) => {
console.log(req.params.email);
};
You can also either use a POST or PUT request in order to access the URL body
router.post("/companyUser/invite", async (req, res, next) => {
console.log(req.body.email);
};

Nodemailer email posting but says pending

I'm trying to use Nodemailer in a React/Express app I'm working on and on the server it says it's posting but in the network tab its showing pending and then it never goes through? Here's my code:
const express = require('express');
const router = express.Router();
const nodemailer = require('nodemailer');
require("dotenv").config();
// router.get('/', () => {
// resizeBy.send('Welcome to my email form')
// });
module.exports = () => {
router.post('/', (req, res) => {
console.log("inside event handler")
let transporter = nodemailer.createTransport({
service: 'Gmail',
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: process.env.EMAIL,
to: `${req.body.values.email}`,
subject: `Message from: ${process.env.EMAIL}`,
html: `
<h3>Information</h3>
<ul>
<li>Name: ${req.body.values.name}</li>
<li>Email: ${req.body.values.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.values.message}</p>
`
}
transporter.sendMail(mailOptions, (err, response) => {
if (err) {
res.send(err)
console.log("Error happened in send email", err)
} else {
res.send('Success! Message sent!')
console.log("Message sent")
}
})
transporter.close();
})
return router;
}
It looks like you don't need to use transporter.close() since you aren't pooling connections. Using it in this context is probably your problem.
transporter.sendMail() is async so you are sending mail and then immediately closing it with transporter.close(). This means the sendMail callback isn't fired, which in turn means res.send() is never sent, which results in your never ending and pending http request to your client.
I suggest removing the transporter.close() line and retrying.

I am using nodemailer but I got an error about ETIMEDOUT without any services

I want to use nodemailer to send the email to the users but I caught en error about ETIMEDOUT but I am not sure what is going on inside the nodemailer module,
const nodemailer = require('nodemailer');
const sendEmail = async (options) => {
// 1-) Create a transporter
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
});
// 2-) Define the email options
const mailOptions = {
from: 'Ogun AÇIĞ <MyEmail> ',
to: options.email,
subject: options.subject,
text: options.message,
//html
};
//3-) Actually send the email
await transporter.sendMail(mailOptions);
};
module.exports = sendEmail;
I have used the EMAIL_HOST,EMAIL_PORT,EMAIL_USERNAME and EMAIL_PASSWORD with my Mailtrap account credentials, if I get the concept of the subject, the message will be send to that Mailtrap account for now. I will change the properties MAIL_HOST,MAIL_PORT,EMAIL USERNAME and EMAIL PASSWORD with information of real user but I need to send a message first.
try {
await sendEmail({
email: user.email,
subject: 'Your password reset token (vaild for 10 minute)',
message,
});
res.status(200).json({
status: 'succes',
message: 'Token sent to email',
});
} catch (error) {
user.passwordResetExpires = undefined;
user.passwordResetToken = undefined;
await user.save({ validateBeforeSave: false });
return next(
new AppError(error.message, 500);
);
}
This is where I got this error. I will be appreciative for your help if you warn me about my mistake.

Categories