react add data from MongoDB to email - javascript

pretty new to react only been doing it for a couple of weeks and I'm working on a project for personal use to send an email to my email using nodemailer which I have managed to do. the next part I want to do is add data to the email that will come from my MongoDB database like the order number, customer name and status of the job I've searched high and low on youtube and google and not really finding anything on the issue
also, it only runs when I type node server.js and then it automatically sends the email which I don't want I want it to run when submit is clicked when a status is updated in the database.
Here is the code for what I have on server.js
require('dotenv').config();
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: 'group2021#gmail.com',
to: 'edge#gmail.com',
subject: 'Project Update',
text: 'Hello {{name}} please find this email as an update to you project.'
};
transporter.sendMail(mailOptions, function(err, data) {
if(err) {
console.log('Error Occured!', err);
} else {
console.log('Email Sent!')
}
});

I'm not sure how your application looks like, I assume it's SPA react application.
I suggest you to create simple http server using Expressjs and creating endpoint which you will call from the client (react app) e.g. (the code is not tested is just an example)
const express = require('express');
const app = express();
const port = 3000;
const nodemailer = require('nodemailer');
app.get('/mail/:someID', async (req, res) => {
// someID is identifier to find data in db
// it will come from localhost:PORT/mail/>>someID<<
const { someID } = req.params;
let data;
try {
data = await mongoCol.FindOne({
/* query */
}); // reads data from mongo
} catch (err) {
return res.status(500).json(err);
}
// prepare content
var text =
'Hello {{name}} please find this email as an update to you project.\n' + data;
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: 'group2021#gmail.com',
to: 'edge#gmail.com',
subject: 'Project Update',
text: text
};
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log('Error Occured!', err);
return res.status(500).json(err);
} else {
console.log('Email Sent!');
return res.sendStatus(200);
}
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
You should add some kind of authorization to not allow other people to send email by your server.
also, it only runs when I type node server.js and then it automatically sends the email which I don't want
This happens because your code is not in function and any time you import or start file (module) it will execute.

Related

How to call a route at a particular time

I have a MERN stack Library Management System website.
In my app currently for admin i have given a Notify button to send emails to all user that have any books due in the library. For this an array of defaulty user gets passed as a req body to send emails. Admin gets this list of users from database on initial render of that particular component.
But i want to automate sending of emails and want my server to trigger automatic emails at 10:00 am to all the users who have due books.
On Notify button click my notifyBookDefaulties controller gets triggered.
I tried to use a setTimeout and a timer as well to call my route at 10:00 am and trigger emails but i am not able to get desired output.
Below i my notifyBookDefaulties controller:
const notifyBookDefaulties = asyncHandler(async (req, res) => {
const admin = await Auth.findById(req.user.id);
// to check if user exists by that id in the databse
// and that user is a admin (got by token)
if (!admin && admin.admin !== true) {
res.status(401);
throw new Error("Not Authorized");
}
const { users, bookID, title } = req.body; // here users is the list of user id's
let emails = "";
// to get email of each user from their user id
for (let user of users) {
try {
const defaulty = await Auth.findById(user);
emails += defaulty.email + ",";
} catch (error) {
res.status(400);
throw new Error(error);
}
}
// to get comma separated list of emails
const emailList = emails.slice(0, -1).toString();
// try block tries to send email and catch block catches any error if occured
try {
var transporter = nodemailer.createTransport({
service: process.env.SERVICE,
auth: {
user: process.env.USER,
pass: process.env.PASS,
},
});
var mailOptions = {
from: process.env.USER,
to: emailList,
subject: "Return Book",
html: `<!DOCTYPE html><html lang="en"><body>This is to remind you that the book titled ${title} and ID ${bookID} issued by you is due.</body></html>`,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
res.status(400).json({ msg: error });
} else {
res.status(200).json({ msg: "E-Mail Successfully sent" });
}
});
} catch (error) {
console.log(error);
res.status(500).json({ msg: error });
}
});
Below is my server.js:
require("dotenv").config();
const express = require("express");
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const cors = require("cors");
const port = process.env.PORT || 5000;
connectDB();
const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 204
};
app.use(cors(corsOptions))
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/api/admin", require("./routes/adminRoutes"));
app.use("/api/user", require("./routes/userRoutes"));
app.use("/api/actions", require("./routes/authRoute"));
app.use(errorHandler);
app.listen(port, () => {
console.log(`Running on ${port}`);
});
My controller gets called for below route:
router.post("/notify", protect, notifyBookDefaulties);
and the url is:
http://localhost:5000/api/admin/notify
Note: here i have not included my function which fetches the list of user id's, of users that have due books. To fetch defaulting users i have a separate controller and i will merge that into this controller once i get the logic to send mails at 10:00 am.
If there is any other way to implement this i would like to know. If any more clarity needed do tell. Thanks in advance.
Sounds like a cron job, check this package https://www.npmjs.com/package/node-cron

Creating an express middleware to send emails

I've been trying to make an express middleware that sends an email using Nodemailer after the previous middleware finishes. I've come up with a few different designs, but ultimately each different version has it's drawback.
Ultimately, I would like the middleware to have a response from the previous middleware. If it is a success, then send a success email, otherwise, send an error email.
I came up with a dual design where one variation pushes to an error middleware, and a success leads to the next middleware. This contains some slight issues of sending multiple headers, specifically on an the second middleware erroring. I could say, if the mail errors out, do nothing. But that doesn't seem right. If anyone has any suggestions on a good design, that would be great.
From what you described, I would suggest not to create different middleware for that, but to just create one generic email function that would handle different type of messages. Then, just use that function in the first middleware and pass different parameters based on use case (success/error).
email-controller.js
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
secure: true,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
});
exports.send_email_message = (send_to, subject, message) => {
return new Promise((resolve, reject) => {
const email_message = {
from: { name: process.env.EMAIL_FRIENDLY_NAME },
to: send_to,
subject: subject,
text: message
};
transporter.sendMail(email_message).then(() => {
resolve(true);
}).catch((error) => {
reject(false);
});
})
}
custom-router.js
const { send_email_message } = require('./email-controller');
const express = require('express');
const router = express.Router();
router.get('/custom-middleware', async (req, res, next) => {
try {
// You can calculate "success" variable based on your custom logic
if(success){
await send_email_message('example#gmail.com', 'Success', 'This is body of success message.');
return res.status(200).json({ success: true });
} else {
await send_email_message('example#gmail.com', 'Error', 'This is body of error message.');
return res.status(400).json({ success: false });
}
} catch(error) {
return res.status(400).json({ success: false });
}
});
module.exports = router;

Send email using Cloud Functions and Nodemailer

How can I send an email to a person using Cloud Functions and Nodemailer?
On my app there's a contact screen where users can ask questions and send feedback to the app, and when the user presses a button, the Cloud Function gets triggered. However, I don't seem to recieve any emails whatsoever, I even checked the "Spam" folder.
What am I doing wrong?
My code for the Cloud Function looks like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
admin.initializeApp(functions.config().firebase);
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'exampleemail#gmail.com',
pass: 'exampleemailpassword'
}
});
exports.sendEmail = functions.https.onRequest((request, response) => {
const { sender, phone, message } = request.query;
const mailOptions = {
from: sender.toLowerCase(),
to: 'exampleemail#gmail.com',
subject: 'New feedback email',
text: `${message} Phone: ${phone}`
};
// eslint-disable-next-line consistent-return
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
response.send(err.toString());
}
response.send('Email sent');
});
});
I see what you are doing wrong, you can't use gmail's SMTP transport service in server environments other than your own computer
Gmail has a limit of 500 recipients a day (a message with one To and
one Cc address counts as two messages since it has two recipients) for
#gmail.com addresses and 2000 for Google Apps customers, larger SMTP
providers usually offer about 200-300 recipients a day for free.
So I would recommend you to use a service like EmailJS to send emails
I was doing it wrong, I had to return a code to the HttpRequest in order to run the function property. Then, it works
exports.sendEmail = functions.https.onRequest((request, response) => {
cors(request, response, () => {
const { sender, phone, message } = request.query;
const mailOptions = {
from: sender.toLowerCase(),
to: 'exampleemail#gmail.com',
subject: 'New feedback email',
text: `${message} \nEmail: ${sender.toLowerCase()}\nPhone: ${phone}`
};
return transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return response.status(500).send({
data: {
status: 500,
message: error.toString()
}
});
}
return response.status(200).send({
data: {
status: 200,
message: 'sent'
}
});
});
});
});

Getting nodeJS web server to send form data to my email

I am trying to get the data my nodeJS server is receiving from a form on the front end to send that data to my email. I have tried to use nodemailer and haven't succeeded much. Can someone tell me perhaps what I am doing wrong with the following code?
const express = require("express");
const app = express();
const nodemailer = require("nodemailer");
var smtpTransport = require("nodemailer-smtp-transport");
const PORT = process.env.PORT || 4000;
app.use(express.static(__dirname + "/front-end"));
app.get("/", (req, resp) => {
resp.sendFile(__dirname + "/front-end/index.html");
});
app.use(express.json());
app.use(express.urlencoded());
app.post("/formData", (req, resp) => {
const data = req.body;
var transport = nodemailer.createTransport(
smtpTransport({
service: "Gmail",
auth: {
user: "user#gmail.com",
pass: "123456",
},
})
);
transport.sendMail(
{
//email options
from: "Sender Name <email#gmail.com>",
to: "Receiver Name <receiver#email.com>", // receiver
subject: "Emailing with nodemailer", // subject
html: data, // body (var data which we've declared)
},
function (error, response) {
//callback
if (error) {
console.log(error);
} else {
console.log("Message sent:");
resp.send("success!");
}
transport.close();
}
);
});
app.listen(PORT, () => {
console.log(`server running on port ${PORT}`);
});
Your code, at a glance, looks fine to me. I think the problem is (since you’re not stating you have set that up), that you want to send email with GMail. If you want to send email from your own app or web service via Gmail, you should set up a project in the Google Cloud Platform. Read more here.
Alternatively, you could use a service like Postmark, which you can configure to send emails via a domain that you own. There’s a free trial. Mailgun is a similar service. (I’m not affiliated to either).

How to use nodemailer with claudia-api-builder

I am trying to create a simple REST API I can post an email to, to then email myself. I am using nodemailer and had set it up as an express app and it all worked fine confirming my authentication etc. is fine. I wanted to host it online so I have used claudia.js to create a lambda and API gateway setup but this seems to have broken it.
The Code
const nodemailer = require('nodemailer');
const secrets = require('./secret');
const apiBuilder = require('claudia-api-builder');
api = new apiBuilder();
module.exports = api;
var mailOptions;
var logMsg = "none";
api.post('/email', async (req, res) => {
mailOptions = {
from: secrets.email,
to: secrets.email,
subject: 'Email From: ' + req.body.senderEmail + ' | ' + req.body.subject,
text: req.body.content,
};
sendMail(mailOptions);
return logMsg;
})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: secrets.email,
pass: secrets.pwd
}
});
function sendMail(mailOptions) {
logMsg="Starting Send Function";
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
logMsg = error;
return error;
} else {
logMsg = "Send Complete";
return true;
}
});
logMsg="Function finished";
}
When I debug via postman, by posting a raw JSON
{
"senderEmail": "test2",
"subject": "test",
"content":"test"
}
I receive "Function Finished" Which I dont really see how it is possible as surely the if or else should've fired under transporter.sendMail(..., returning from the function. I also don't receive an email which is my end goal
I had the same problem until I started returning the transporter
return transporter.sendMail(mailOptions)
.then(info => {
console.log('email sent: ', info)
return {'status': 'OK'}
})
.catch(err => {
console.log('email error: ', err)
return {'status': 'ERROR'}
})

Categories

Resources