I Have issue with sending email from my react app. I have BE in nodeJS deployed on HEROKU. For sending emails I'm using Nodemailer. The point is that everything works fine. Email is sent and deliver. But I don't know why I'm getting 503 status code.
I read heroku documantation where it says that the reason why is that can be infinite loop. But I think I don't have infinity loops here.
Thank you for any kind of help.
Here is my code:
const express = require("express");
const nodemailer = require("nodemailer");
const cors = require("cors");
const bodyParser = require("body-parser");
const app = express();
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post("/send", async (req, res) => {
console.log("req: ", req.body);
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.firstName}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phoneNumber}</li>
<li>Created: ${req.body.createdAt}</li>
</ul>
<h3>Message</h3>
<p>Hi there</p>
`;
let transporter = nodemailer.createTransport({
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
secure: true, // true for 465, false for other ports
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
});
// send mail with defined transport object
try {
await transporter.sendMail({
from: "test#test.sk",
to: "info#test.sk",
subject: "Hello ✔",
text: "Hello world?",
html: output,
});
console.log("Objednávka bola úspešne odoslaná");
return res;
} catch (error) {
console.log("error: ", error);
return error;
}
});
const port = process.env.PORT || 3001;
app.listen(port, () => console.log("Server started"));
You're not sending back any response from your POST handler, you're either returning res or error, both of which don't do anything in Express, which means requests will never properly end.
Instead, send back a proper response to end the request:
return res.end(); // for a normal situation
return res.status(400).end(); // for an error situation
It's up to you if you want to send back some text, or to set another status code that's more appropriate in your app.
Related
I am a beginner in server side programming. Trying to write code that will allow me to get data from state variable, send it to my backend and use nodemailer service to send it to an email adress. My frontend is as follows :
const handleSubmit = async () => {
try {
await axios.post(
"http://localhost:2525/send_mail",
{
state
}
);
} catch (error) {
console.log(error);
}
};
state gets sent to backend :
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const nodemailer = require('nodemailer');
require('dotenv').config();
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.options('',cors());
app.get('/', (req, res) => {
res.send('Server is running');
});
app.post("/send_mail", cors(), async (req, res) => {
let { state } = req.body;
const transport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'adress#mail.com',
pass:'password'
}
});
await transport.sendMail({
from: '<myemail.#example.com>',
to: "reciever#example.com",
subject: "test email",
html: `<div><p>${state.Message}</p></div>`
});
});
app.listen(process.env.PORT || 2525, () => { console.log("Server is running"); });
If it matters, state is an object that gets filled from form data, it looks something like :
const data = {
FirstName: "",
LastName: "",
Message:"",
};
When i visit port 2525, server is indeed running with the message i gave it. But when i try to submit my form with "handleSubmit", i get the following console error:
*>
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:2525/send_mail. (Reason: CORS request did not succeed). Status code: (null).*
And it crashes the server
As you can see i am already using cors middleware to try to handle it.
I tried adding a proxy to the package.json file, as : "proxy": "http://localhost:2525", ( i did not change anything else when i did that, i don't know if that is the correct way). This did not solve anything, but at least the server did not crash any more. Instead, the POST request gets a 404:
*
POSThttp://localhost:2525/send_mail Referrer Policystrict-origin-when-cross-origin*
I tried running it in Chrome, same problem. I tried everything i could read on stackoverfrlow google or chat gpt, really that is cors-related. Even checked if port is maybe taken by something else in windows, checked that in cmd. Im at my wits end really
I have used nodemailer/axios to get information from a form to be sent to an e-mail address.
When the site is run with localhost:3000 the mail gets sent no problem, although live it does not come through.
I am assuming it has to be something to do with the proxy?
This is what my code looks like which works:
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.user(proxy("/api", { target: "http://localhost:3000"}))
}
the live site is at: https://deathless-studio.netlify.com/#/
I tried changing the target to that, as well as: https://deathless-studio.netlify.com/ and also http://deathless-studio.netlify.com/#/, although no mail gets sent through.
I always get these errors:
https://deathless-studio.netlify.com/api/v1/sendMail 404
POST https://deathless-studio.netlify.com/api/v1/sendMail 404
my send mail function looks like this:
const sendEmail = (name, email, message, newsletter) => {
const smtpTransport = mailer.createTransport({
service: "Gmail",
auth: {
user: "(correct email)",
pass: "(correct password)"
}
})
const mail = getEmailData(name, email, message, newsletter)
smtpTransport.sendMail(mail, function(error, response) {
if(error) {
console.log(error)
} else {
alert( "Thank you! We will be in touch shortly!")
}
smtpTransport.close();
})
the handleSubmit function on my Form Component looks like this also:
handleSubmit(event) {
event.preventDefault();
const data = {
name: this.state.name,
email: this.state.email,
message: this.state.message,
newsletter: this.state.newsletter
};
Axios.post("api/v1/sendMail", data)
alert( "Thank you! We will be in touch shortly!")
}
and my index.js looks like this:
const server = require("./server");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json());
server.use(cookieParser());
const { sendEmail } = require("../server/routes/mail");
server.post("/api/v1/sendMail", (req, res) => {
sendEmail(req.body.name, req.body.email, req.body.message, req.body.newsletter);
});
const port = process.env.PORT || 3000;
server.listen(port, () => {
// eslint-disable-next-line no-console
console.log("Server listening on port", port);
});
Any ideas on how to fix this?
Greatly appreciated.
So it turns out Netlify doesn't use a Node.js server and you can use their plugins instead.
This article explains it:
https://community.netlify.com/t/node-js-wont-start-trying-to-run-a-server-on-netlify/3454/2?fbclid=IwAR0wc4iLhFdS-_dZF4TGPyzONmfHQxwfEztNFO2oTTlonrsBwCF73Xf7QNY
I have been creating the system for several hours. I almost put the project into an end, but somehow I cannot receive any emails after filling the form. Does anyone know what is the cause of this problem ??
First, I installed node.js, then nodemon. I have four main files and a folder in the project folder - app.js, package-lock.json, contact.handlebars, package.json and node_module.
the code below is app.js
const express = require("express");
const bodyParser = require("body-parser");
const exphbs = require("express-handlebars");
const path = require("path");
const nodemailer = require("nodemailer");
const app = express();
// view engine setup
app.engine("handlebars", exphbs());
app.set("view engine", "handlebars");
// Static folder
app.use("/public", express.static(path.join(__dirname, "public")));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get("/", (req, res) => {
res.render("contact", { layout: false });
});
app.post("/send", (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "I PUT 1ST SERVERNAME HERE OF HOSTGATOR",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "MY 1ST EMAIL ACCOUNT", // generated ethereal user
pass: "********" // generated ethereal password
},
tls: {
rejectUnauthorized: false
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Nodemailer Contact" <MY 1ST EMAIL ACCOUNT>', // sender address
to: "MY SECOND EMAIL ACCOUNT", // list of receivers
subject: "Node Contact Request", // Subject line
text: "Hello world?", // plain text body
html: output // html body
});
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
res.render("contact", { layout: false }, { msg: "Email has been sent" });
}
main().catch(console.error);
});
app.listen(3000, () => console.log("server started..."));
Ethereal's test SMTP service doesn't send the emails. From their website:
It's a completely free anti-transactional email service where messages never get delivered.
It looks like it lets you view a preview of the sent mail to check your application is working correctly, but to actually send email you need to set up a real SMTP server. You can get SMTP credentials for sending transactional mail from applications from various companies such as SendGrid and Mailgun.
I deployed an app on heroku with angular for the front-end and node(express) as the back-end. On the contact page, I have a form that will be sent via email once the send button is pressed, which then sends the info via HTTP to node for the user inputs to be passed through the node function - I'm using SendGrid addon for the email process to send the email. I tried multiple time, but I just can't get it to work and can't find a tutorial with angular. It worked before with nodemailer on the localhost, but I can't figure it out once it is deployed. Thank you a lot for your time.
node code app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const sgMail = require('#sendgrid/mail');
const port = process.env.PORT || 3000;
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'client')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client/index.html'));
});
app.post('/client-contact', (req, res) => {
const clientMsg = `
<p> Email sent from your portfolio website</p>
<h3>Contact details</h3>
<ul>
<li>Name ${req.body.name}</li>
<li>Email: ${req.body.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'mrwanzein#outlook.com',
from: 'mrwanzein#outlook.com',
subject: 'Angular portfolio form user response',
html: clientMsg,
};
sgMail.send(msg);
});
app.listen(port, () => {
console.log(`Server is on on port ${port}`);
});
the function that register the user input and then sends it to node (and handles some validations, the interest is the last line) contact.component.ts
sendMail() {
var name = <HTMLInputElement>document.getElementById('inputName'),
email = <HTMLInputElement>document.getElementById('inputEmail'),
msg = <HTMLInputElement>document.getElementById('inputMsg');
var obj = {
name: name.value,
email: email.value,
message: msg.value
}
let validateEmail = () => {
const re = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?
^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])/;
return re.test(email.value);
}
if(!name.value || !email.value || !msg.value || !validateEmail()) {
this.bool = true;
} else {
this.bool = false;
setTimeout(() => {
window.location.reload()
}, 1500);
return this.http.post('https://mrwanzein.herokuapp.com/client-contact', obj).subscribe();
}
}
You need to configure an SMTP server for your application.
The easiest way is with a heroku addin such as mailgun
I fixed it, basically the code is fine, I had to remove the res.send() around sgMail.send(msg) and I forgot to ng build(angular) to update the HTTP address when I changed it. I was pushing changes to the repo without the missing updated code, oh dear... :P
I think I'm missing something very simple here. I have a simple, one page node.js app that uses nodemailer to email any form data to my inbox.
My index.js file:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'myemail#gmail.com',
pass: 'mypassword'
}
});
app.use(express.static('public')); //public folder with my html files
app.get('', function (req, res) {
res.sendFile(__dirname + "/");
})
app.post('/', function (req, res) {
response = {
name: req.body.name,
email: req.body.email,
message: req.body.message
};
var mailClient = {
from: 'myemail#gmail.com',
to: 'myemail#gmail.com',
subject: `Message from ${response.name}`,
text: 'MyMessage'
};
transporter.sendMail(mailClient, function (error, info) {
if (error) {
console.log(error); //not happening
} else {
res.redirect("/success.html"); //also not happening
}
});
})
var server = app.listen(80, function () {
var host = server.address().address
var port = server.address().port
console.log("App listening at http://%s:%s", host, port)
})
When I run this on my local machine using npm start in the root directory, the app runs perfectly fine on localhost. Nodemailer works properly; when I submit, my form data gets emailed to myself and I get redirected to my success page.
However, when I deploy this to Firebase, it seems the nodemailer part doesn't work. The page loads in with my static files, but when I try to submit anything via the form, the page simply refreshes (like when you have a submit button with bare html), instead of redirecting me to my success page and emailing data.
Is there something I need to change in my code to make it work with firebase?
Edit - no logs:
Google requires a paid account in order to make use of "Outbound Networking". The Free Tier does not allow you to make outbound calls. This would include sending mail to a remote mail server (like sending an email to a Yahoo, Gmail, or Outlook account).
See their pricing page for more info.
Look for "Outbound Networking".
If you'd like to leverage Gmail's API, you should still be able to use nodemailer with firebase functions and achieve what you're looking for and remain on the Free Tier. A fully working example is already available in the firebase-samples repository! I would like to highlight what the linked tutorial mentions, which is that Gmail does have an email sending quota that you should be aware of.
I tried to figure out problem in your code but didn't found any, I also have functionality to send email with verification code for authenticate/verify email id. For that I create one gmail id and gave that id/password for sending mail. Mails are sent from that gmail id with node.js when ever user register is email id we send email with veirfication code. My code is as under:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
var bodyParser = require('body-parser');
var users = require('./users/route');
const app = express();
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = 'myapp#gmail.com';
const gmailPassword = 'password';
const gcm = require('node-gcm');
const mailTransport = nodemailer.createTransport(
`smtps://${gmailEmail}:${gmailPassword}#smtp.gmail.com`);
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myapp.firebaseio.com"
});
//admin.initializeApp(functions.config().firebase);
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const authenticate = (req, res, next) => {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer')) {
res.status(403).send('Unauthorized');
return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
req.user = decodedIdToken;
next();
}).catch(error => {
res.status(403).send('Unauthorized');
});
};
app.get("/token", (req, res) => {
res.status(200).send(admin.auth().applicationDefault());
admin.auth().createCustomToken(req.query.uid)
.then(function (customToken) {
res.status(200).send(customToken);
})
.catch(function (error) {
console.log("Error creating custom token:", error);
});
});
// GET /api/verifyEmail?code="1234"
app.get('/verifyEmail', (req, res) => {
// Get the one-time code from the query parameter.
var verificationCode = req.query.code;
var displayName = req.query.displayName;
var email = req.query.email; //If GET request
const mailOptions = {
from: `Linkuni <noreply#firebase.com>`,
to: email
};
// The user subscribed to the newsletter.
mailOptions.subject = `Welcome to Linkuni`;
mailOptions.text = `Hi ${displayName || ''}\n\n Welcome to Linkuni. We hope you will enjoy our service. Please enter this code:${verificationCode} into the app.\n\nThank you,\nLinkuni Team`;
return mailTransport.sendMail(mailOptions).then(() => {
console.log('Verification email sent to:', email);
});
});
Hope this helps!! :)