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).
Related
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
i am trying to lock up my swagger documentation, i am using express basic auth for this, when i try to access the documentation endpoint it just throws a HTTP ERROR 401 without asking me to provide a username and password.
app.use("/api-docs",basicAuth({
challenge: true,
users: { 'me': 'openforme' } }),
swaggerUi.serve,
swaggerUi.setup(yaml.parse(swaggerfile))
);
when i remove the basicauth middleware i can access the endpoint, what i want is a popup to into the username and password.
use the Nub-auth package
const express = require('express');
const nubAuth = require('nub-auth');
app = express();
app.use(['/v1'], nubAuth({
challenge: true,
users: { 'admins': 'admin', 'users': 'user', 'guest': 'guested' }
}));
app.get('/api', (req, res) => {
res.send('Hello World welcome to API endpoints free !');
});
app.get("/v1", (req, res) => {
res.send("Hello World welcome to API endpoints closed !");
});
from my investigation edge does not have the basic auth feature enabled.
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.
I've got a problem with sending e-mails from my (let's say) contact form. It works brilliant when I'm connected to only two networks: my mobile hotspot and at my office. When I'm connected to any other network with internet access, it doesn't work (there are no errors, but no e-mails as well :( ... )
At first time I used SendGrid and I thought that the problem is within SendGrid. I even contacted with SendGrid support team and I was said, that code is correct and my settings are also allright.
In the next step I tried a Nodemailer - unfortunatelly the same effect...
Need a clue, what might be a problem?
Below is my code responsible for creating and sending e-mail request:
Here's a code
const express = require("express");
const cors = require("cors");
const sgMail = require("#sendgrid/mail");
require("dotenv").config();
const API_KEY = process.env.REACT_APP_SG_MAIL_API_KEY;
sgMail.setApiKey(API_KEY);
const app = express();
app.use(cors());
app.get("/", (req, res) => {
res.send("Hello");
});
app.get("/send-email", (req, res) => {
const { recipient, sender, topic, html, senderName } = req.query;
let subject = topic + senderName;
const msg = {
to: recipient,
from: sender,
subject: subject,
html: html
};
sgMail.send(msg).then();
});
app.listen(4005, () => {
console.log("Server 4005 is listening");
});
As I said before - it works perfect with two specific networks mentioned above.
EDIT:
Here is my fetch request:
fetch(
`${window.location}/send-email?recipient=${email.recipient}&sender=${
email.sender
}&topic=${email.subject}&html=${myhtml}&senderName=${senderName}`,
{ mode: "no-cors" }
).catch(err => console.log(err));
My use case:
My case is that i'm making a bot for listening podcast in which user will make call to twilio number and bot will ask what type of podcast would you like to listen then record for 10 seconds
when recording finish, it say user to please wait while we are finding podcast
I want that recording in my webhook so i will figure out caller mood and find appropriate podcast mp3 file from my database and play to caller
Issue I'm Facing:
I'm getting empty body in all of my webhooks
My code:
var express = require("express");
var bodyParser = require("body-parser");
var VoiceResponse = require('twilio').twiml.VoiceResponse;
var app = express();
var port = (process.env.PORT || 4000);
app.use(bodyParser.json())
// helper to append a new "Say" verb with alice voice
function say(text, twimlRef) {
twimlRef.say({ voice: 'alice' }, text);
}
// respond with the current TwiML content
function respond(responseRef, twimlRef) {
responseRef.type('text/xml');
responseRef.send(twimlRef.toString());
}
app.post("/voice", function (request, response, next) {
console.log("request: ", request.body); //body is comming as empty object
var phone = request.body.From;
var input = request.body.RecordingUrl;
var twiml = new VoiceResponse();
console.log("phone, input: ", phone, input);
say('What type of podcast would you like to listen. Press any key to finish.', twiml);
twiml.record({
method: 'POST',
action: '/voice/transcribe',
transcribeCallback: '/voice/transcribe',
maxLength: 10
});
respond(response, twiml);
});
app.post("/voice/transcribe", function (request, response, next) {
console.log("request: ", request.body); //body is comming as empty object
var phone = request.body.From;
var input = request.body.RecordingUrl;
var twiml = new VoiceResponse();
var transcript = request.body.TranscriptionText;
console.log("transcribe text: ", transcript);
//here i will do some magic(Ai) to detect user mood and find an
//appropriate mp3 file from my database and send to twilio
var mp3Url = 'https://api.twilio.com/cowbell.mp3'
say('start playing.', twiml);
twiml.play(mp3Url);
respond(response, twiml);
});
app.listen(port, function () {
console.log('app is running on port', port);
});
API Test with postman:
added url as webhook on twilio:
Heroku Logs:
Twilio developer evangelist here.
You are using body-parser which is good. However, you are using the JSON parser. Twilio makes requests in the format of application/www-x-form-urlencoded so you should change:
app.use(bodyParser.json())
to
app.use(bodyParser.urlencoded({ extended: false }))
Then you should see the parsed body as part of the request.body object.
As an extra note, the transcribeCallback is sent asynchronously to the call. So returning TwiML in response to that request won't affect the call at all. You will need to modify the call in flight, by redirecting it to some new TwiML when you get the result of transcription. An example of updating a call with Node.js is below:
const accountSid = 'your_account_sid';
const authToken = 'your_auth_token';
const client = require('twilio')(accountSid, authToken);
client.calls('CAe1644a7eed5088b159577c5802d8be38')
.update({
url: 'http://demo.twilio.com/docs/voice.xml',
method: 'POST',
})
.then((call) => console.log(call.to));