Nodemailer email posting but says pending - javascript

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.

Related

Send data from script.js to Node.js file (Using Sendgrid API)

Trying to insert data into a node.js server file from a submit event on another js.file client.
But it wont work could you see if there is any wrong with code? Looks kinda good to me but ofcourse something is wrong.
Client submit event code
`window.onload = function() {
document.getElementById('contact-form').addEventListener('submit', function(event) {
event.preventDefault();
const customMessage = document.getElementById('contact-form');
$.post("/request", {
mes: customMessage
}, function(data, status) {
console.log(data);
});
});
}`
Server node js code
// require necessary modules
`const express = require('express');
const bodyParser = require('body-parser');
const sgMail = require("#sendgrid/mail");
require('dotenv').config({ path: './dist/sendgrid/.env' });`
// set up the express app
`const app = express();
const port = process.env.PORT || 3000;`
// use body-parser middleware to parse request body
`app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());`
// set up the SendGrid API key
`sgMail.setApiKey(process.env.SENDGRID_API_KEY);`
// define route to handle POST request from client
`app.post('/request', async (req, res) =\> {
try {
// extract message from request body
const { mes } = req.body;
`
// send email using SendGrid
` await sgMail.send({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text not working',
text: mes
});
console.log('Email sent successfully');
res.status(200).send('Email sent successfully');`
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
res.status(500).send('Internal server error');
}
});`
// start the server
`app.listen(port, () =\> {
console.log(`Server started on port ${port}`);
});
`
This is basic code that is working on single execute:
`
require("dotenv").config();
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const sendMail = async(msg) =\> {
try{
await sgMail.send(msg);
console.log("message sent succes");
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
}
};
sendMail({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text',
text: "this test works"
});`

Nodemailer not sending email, displays "Message sent:Undefined"

It was working and then it wasn't. I sent a few mails and after a while it stopped working. I get
"Message sent:Undefined"
(node:9048) UnhandledPromiseRejectionWarning: Error: spawn sendmail ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
I have no idea why.
Frontend- Axios console logs the response data therefore the server and the frontend both are working. It is just the issue with the Nodemailer.
Any help is appreciated. Thanks!
const express = require("express");
const app = express();
const cors = require("cors");
const nodemailer = require("nodemailer");
const path = require("path");
const fs = require("fs");
const readData = path.join(__dirname, "../email_take2/data.json");
const { v4: uuidv4 } = require("uuid");
app.use(express.json());
app.use(cors());
const port = process.env.PORT || 5000;
app.listen(5000, () => console.log(`Listening at port ${port}`));
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("../client/build"));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
});
}
function listUserData() {
const data = fs.readFileSync(readData);
return JSON.parse(data);
}
app.post("/sendEmail", function (req, res) {
console.log(req.body);
const emailInfo = {
id: uuidv4(),
email: req.body.email,
cc: req.body.cc,
message:req.body.message,
};
const dataArray = listUserData();
dataArray.push(emailInfo);
fs.writeFileSync(readData, JSON.stringify(dataArray));
res.send(emailInfo);
console.log("SentBody", emailInfo);
let transporter = nodemailer.createTransport({
sendmail:true,
host: "smtp.outlook.com",
port: 587,
secure: false, // true for 465, false for other ports
tls: {
ciphers: "SSLv3",
},
auth: {
user: "memail#outlook.com", // generated ethereal user
pass: "mypw", // generated ethereal passwordAccount.pass,
},
});
// send mail with defined transport object
let info = transporter.sendMail({
from: '"Fred Foo 👻" <foo#example.com>', // sender address
to: "garbageacc7878#outlook.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
return emailInfo;
});
transporter.sendMail returns a promise, that's why your console log has undefined. So either attach a .then and .catch.
transporter.sendMail(...)
.then((data)=>{console.log('Mail sent', data)})
.catch(err => {console.error('Failure',err)})
Or make your request handler an async function and use async await and use tryCatch.
try{
let data = await transporter.sendMail(...)
console.log('Mail sent', data)
} catch (err) {
console.error('Failure',err)
}

Express returns servers' automatic HTML error page, instead of my res.json error message

I have a REST api on the express server and React app for front-end. I have designed it to send JSON to front-end when faces an error, it sends it and I can use it to print errors on the client side as a modal etc. this is my route file for user/login(I also use JWT and bcrypt for password issues):
router.post("/login", (req, res) => {
const { email, password } = req.body;
//simple validation
if (!email || !password) {
return res.status(400).json({ general: "Email and Password can not be empty" });
}
//check for existing user
User.findOne({ email }).then((err, user) => {
if (!user)
return res.status(400).json({ email: "This user doesn't exist"});
if (err) console.log(err);
//Validate password
bcrypt.compare(password, user.password).then(isMatch => {
if (!isMatch)
return res
.status(400)
.json({ password: "Password and User name are not match!" });
jwt.sign(
{ id: user.id },
config.get("jwtSecret"),
{ expiresIn: 3600 },
(err, token) => {
if (err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email,
sort: user.sort
}
});
}
);
});
});
});
and my app.js:
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const config = require("config");
const app = express();
//Bodyparser Middleware
app.use(bodyParser.json());
// DB config
const db = config.get("mongoURI");
//connect to Mongo
mongoose
.connect(db)
.then(() => console.log("MongoDB Connected..."))
.catch(err => console.log(err));
//Use routes
app.use("/api/test", require("./routes/api/test"));
app.use("/api/users", require("./routes/api/users"));
app.use("/api/tickets", require("./routes/api/tickets"));
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
On Localhost there is no problem. But after uploading to the server, when I left empty spaces or submit false password etc, it never sends my JSON responses, instead, it returns servers Html Page. I console.logged returning error response and it is something like this:
How can I replace the Html response with my own JSON error message?
The default error handler shows the error as an HTML page.
See https://expressjs.com/en/guide/error-handling.html
You can override the default error handler. Try adding this to the end of your app.js.
// catch 404 and forward to error handler
app.use(function (req: express.Request, res: express.Response, next) {
next({ status: 404 });
});
app.use(function (err: any, req: express.Request, res: express.Response, next: express.NextFunction) {
console.error(err);
res.status(err.status || 500).json();
});
i guess you are using axios?
did you try it with:
.then(err => {
err.response.data
})
Your response is actually in err.response

Nodemailer not sending e-mail after successful stripe payment charge

I am trying to send an email to myself after a purchase has been made via stripe. I currently have a personal and business email that I am using for this. I am new to node.js, and I'm confused as to why this is not working.
What makes sense to me is to add this code as an argument to the .then callback. When testing this out locally, the success page renders, however no emails are sent and the two console.log's at the bottom are not being outputted to the console. The following is my app.js
const express = require('express');
const stripe = require('stripe')('mystripekey');
const bodyParser = require('body-parser');
const exphps = require('express-handlebars');
const nodemailer = require('nodemailer')
var app = express();
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'myemail#gmail.com',
pass: 'mypassword'
}
});
app.engine('handlebars', exphps({defaultLayout: 'main'}));
app.set('view engine', 'handlebars')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static(`${__dirname}/public`));
app.get('/', (req, res) => {
res.render('index');
});
app.post('/charge', (req, res) => {
const amount = 25000;
stripe.customers.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer => stripe.charges.create({
amount,
description: 'Advertisement',
currency: 'usd',
customer: customer.id
}))
.then(charge => {
// This is where I'm getting confused
res.render('success')
var mailOptions = {
from: req.body.stripeEmail,
to: 'mybizemail#gmail.com',
subject: 'A purchase was made',
text: req.body.stripeEmail + ' made a purchase!'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
});
});
I expected either an error message to be logged or the email sent to be logged but that is not happening. Any help is greatly appreciated.
I think the node mailer code is never getting called. Try putting the res.render in callback in transporter.sendMail.
Like so:
.then(charge => {
console.log("charge>", charge);
var mailOptions = {
from: req.body.stripeEmail,
to: 'mybizemail#gmail.com',
subject: 'A purchase was made',
text: req.body.stripeEmail + ' made a purchase!'
};
console.log("mailOptions>", mailOptions);
transporter.sendMail(mailOptions, function(error, info){
console.log("error1>", error);
console.log("info>", info);
if (error) {
console.log(error);
res.render('error')
} else {
console.log('Email sent: ' + info.response);
res.render('success')
}
});
});

Show progress while sending multiple emails

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

Categories