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

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

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

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.

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.

How do i send a success status code to the front end using node.js?

I have recently started using node.js as my backend and I have successfully posted data to the database, the problem that I am facing now is telling the front end that data has been successfully saved. Below is my user route with all the things I have tried commented out.
import { Router } from 'express';
import { IUser } from '../models/user.model';
const User = require('../models/user.model');
// import bcrypt from 'bcrypt';
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
// create application/json parser
var jsonParser = bodyParser.json()
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
const userRouter = Router();
userRouter.get('/', (req, res) => {
return res.json('This is the user route');
})
userRouter.post("/register", (req, res: any, next) => {
const user: IUser = new User({
email: res.email,
firstName: res.firstName,
lastName: res.lastName,
password: res.password,
displayName: res.displayName,
cellNumber: res.cellNumber,
});
user.save()
.then((result: any) => {
res.status(201).json({
message: 'Successfully created a new user!',
result: result
});
// res.sendCode(201);
// console.log(res);
// res.status(201).send("User has been successfully created");
//return 'User has been successfully created';
// return Object({ message: "User has been successfully created" });
// return res.status(201).send({
// message: "User has been successfully created",
// statusCode: 201
// })
// return res;
})
.catch((err: any) => {
res.status(500).json({
error: err
})
})
// bcrypt.hash(req.body.password, 10)
// .then((hash: string) => {
// const user = new User({
// email: req.body.email,
// firstName: req.body.firstName,
// lastName: req.body.lastName,
// password: hash,
// displayName: req.body.displayName,
// cellNumber: req.body.cellNumber,
// });
// user.save()
// .then((res: any) => {
// res.status(201).json({
// message: 'Successfully created a new user!',
// result: res
// });
// })
// .catch((err: any) => {
// debugger;
// res.status(500).json({
// error: Error
// })
// })
// })
})
export default userRouter;
which I then export to the server.ts file which is below
import express = require('express');
//import cors from 'cors';
const cors = require('cors');
const bodyParser = require('body-parser')
import { Router } from 'express';
import mongoose from "mongoose";
import "dotenv/config"
//routes
import userRouter from './routes/user.routes';
//Create a new express instance
const app: express.Application = express();
app.get('/', function (req, res) {
res.send('Hello World');
});
// //get router
// var router = express.Router();
//Database
mongoose.connect(`${process.env.MONGO_URI}`,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log("Connected to MongoDB")
})
.catch(() => {
console.log("Connection to Database has failed")
})
var corsOptions = {
origin: '*',
credentials: true,
methods: '*'
};
const routes = Router();
export default routes;
app.use(routes);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors(corsOptions));
app.use("/user", userRouter);
routes.use('/user', userRouter);
routes.use(cors(corsOptions));
//use cors middleware
// router.use(cors(options));
app.listen(3000, function () {
console.log('App is listening on port 3000!');
})
What is strange is that when I set breakpoints and analyse the res file, i can see the data that I would have posted from the front end. But the front end gets the 500 status code instead of the 201 that I want to be sending, even though it passes right over that code. I have googled the keys of my keyboard for three days now. So I am at a loss now.
All The latest changes can be found in the GitLab repository below
https://gitlab.com/ShanahJr/SuperiorBallers
You just need to make use of res variable provided by express.
Example -
module.exports.updateData = async (req, res, next) => {
try {
const data = await Editor.edit(req.body.query);
res.status(200).json({ "status": true, "result": 'Edit successful!' })
} catch (error) {
console.log(error)
res.status(200).json({ "status": false, "result": "Request Failed!" })
}
}
This statement - res.status(200).json({ "status": true, "result": 'Edit successful!' })
Nowadays, express also suggests using res.sendStatus(200) over res.status(200)
You can lookup for status codes here
Use res.status(201).send(), res.status().json usually gets blocked by http rules especially when you activate https

req.body is undefined after post request

I'm building a contact form using nodemailer.
To post it I'm using the fetch API.
But for some reason, I get req.body as undefined.
Here's the frontend code:
form.onsubmit = function (e) {
// Stop the regular form submission
e.preventDefault();
const name = document.querySelector("form#contactForm #name").value;
const email = document.querySelector("form#contactForm #email").value;
const textarea = document.querySelector("form#contactForm #textarea").value;
// Collect the form data while iterating over the inputs
var data = {};
data = { name, email, textarea };
console.log(data);
fetch("/mail", {
method: "POST", // or 'PUT'
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
})
.then(async (response) => {
if (response.ok) {
return response.json();
} else {
const resJson = await response.json();
console.log(resJson);
if (typeof resJson.errors === "undefined") {
formStatus.className += " alert-danger";
formStatus.innerText =
"An error occured, Please refresh the page. Or email us at ravchesed#kehilasbelz.be";
return;
}
let ul = document.createElement("ul");
resJson.errors.forEach((err) => {
const li = document.createElement("li");
li.innerText = `${err.msg}: ${err.param} `;
ul.append(li);
console.log(`${err.msg}: ${err.param} `);
});
formStatus.className += " alert-danger";
formStatus.innerText = "";
formStatus.append(ul);
throw response;
}
})
.then((data) => {
console.log("Success:", data);
})
.catch((error) => {
console.error("Error:", error);
});
};
Here's the backend:
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const { check, validationResult } = require("express-validator");
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // limit each IP to 100 requests per windowMs
});
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const mail = express.Router();
// app.post("/mail", (req, res) => {
// console.log(req.body);
// const result = {
// hellop: 5
// };
// res.send(JSON.stringify(result));
// });
mail.post(
"/mail",
// limiter,
[
// username must be an email
check("email").trim().isEmail(),
check("textarea").trim().isLength({ max: 6000 }),
check("name").trim().isLength({ min: 2, max: 20 }),
],
(req, res) => {
console.log(req.body); //undefined
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors); //this returns empty values.
return res.status(422).json({ errors: errors.array() });
}
const mailInfo = {
name: req.body.name,
email: req.body.email,
message: req.body.testarea,
};
main(mailInfo).catch(console.error);
res.json({ success: true });
}
);
const nodemailer = require("nodemailer");
// async..await is not allowed in the global scope, must use a wrapper
async function main(data) {
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "xxx.xxx.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "email#example.com", // generated ethereal user
pass: "abc123456", // generated ethereal password
},
});
// send mail with defined transport object
let info = await transporter.sendMail(
{
from: '"John Doe 👍" <robot#Doe.dev>', // sender address
to: "Doe#gmail.com", // list of receivers
subject: `📧 Mail from ${data.name}`, // Subject line
html: `
<b>${data.name}, ${data.email}</b><br>
Phone: ${data.phone}<br>
<br>
Message:
<br>
${data.message}
`, // html body
},
function (err, info) {
if (err) console.log(err);
else console.log(info);
console.log("Message sent: %s", info);
}
);
}
module.exports = mail;
Looked at a lot of posts, but this seems to be a different problem.
after looking at everything again I know where my mistake was but don't understand why.
My file structure is like this:
app.js
mail.js
mail.js was imported to app.js like this:
//handle mail
const mail = require("./mail");
app.use(mail);
in app.js I didn't import body-parser and the middleware because it was already imported in mail.js.
but looks like for some reason that I also have to import it in app.js before mail.js.

Categories