POST 405 (Not Allowed) after deploying on heroku - node.js

this is my first time using React and Node.js to create a web app that has a contact form using nodemailer and axios. Everything seems to be working on localhost, however, after I deployed it on heroku, I got a "POST https://myapp.herokuapp.com/ 405 (Not Allowed)" when I try to send an email using the form
my index.js
const path = require('path');
const express = require('express');
const rateLimit = require("express-rate-limit");
const transporter = require('./config');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const buildPath = path.join(__dirname, '..', 'build');
const PORT = process.env.PORT || 3030;
app.use(express.json());
app.use(express.static(buildPath));
const limiter = rateLimit({
windowMs: 30 * 1000, // 30 seconds
max: 1 // limit each IP to 1 requests per windowMs
});
// apply to all requests
app.use(limiter);
app.post('/send', (req, res) => {
try {
const mailOptions = {
from: req.body.email,
to: process.env.email,
subject: req.body.subject,
html:
`<p>New Contact Request</p>
<h2>Contact Details</h2>
<ul>
<li>Name: ${req.body.name}</li>
<li>Email: ${req.body.email}</li>
<li>Subject: ${req.body.subject}</li>
<li>Message: ${req.body.message}</li>
</ul>
`
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) {
res.status(500).send({
success: false,
message: 'Something went wrong. Please try again'
});
}
else {
res.send({
success: true,
message: 'Thanks for contacting me. I will get back to you soon'
});
}
});
}
catch (error) {
res.status(500).send({
success: false,
message: "Something went wrong. Please try again"
});
}
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, '../build/index.html'), function (err) {
if (err) {
res.status(500).send(err)
}
})
})
app.listen(PORT, () => {
console.log(`Server Started at PORT ${PORT}`);
});
my emailConfig.js
const nodemailer = require('nodemailer');
const dotenv = require('dotenv');
dotenv.config();
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.email,
pass: process.env.password
}
});
module.exports = transporter
my contact.js
import React, { useState } from 'react';
import './Contact.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Form, Button } from 'react-bootstrap';
import axios from 'axios';
const Contact = () => {
const [state, setState] = useState({
name: '',
email: '',
subject: '',
message: ''
});
const [result, setResult] = useState(null);
const sendEmail = event => {
event.preventDefault();
axios
.post('/send', { ...state })
.then(response => {
setResult(response.data);
setState({ name: '', email: '', subject: '', message: '' });
})
.catch(() => {
setResult({ success: false, message: 'Something went wrong. Please try again'});
});
};
const onInputChange = event => {
const { name, value } = event.target;
setState({
...state,
[name]: value
});
};
return (
//some html code
);
};
export default Contact;
I've tried adding a Procfile (my index.js is inside a folder called server)
web: node server/index.js
after adding the Procfile and redeployed, I can't even access the website anymore, but instead, an error saying "GET https://my app.herokuapp.com/ 503 (Service Unavailable)"

First of all I'm facing few technical moments.
From my experience I can say show it should be:
Your node.js application should be hosted directly on http and https default ports 80, 443, or behind proxy ex Nginx (You can choose any other). There are some restrictions by browsers when using different ports.
Look inside axios config, when you're posting to send it goes to your app url, but there is no port defined.
Another, more native option is to use react fetch.
It's just how I see software design, so try to deploy your application as api and call it via postman and then from local copy of your frontend.

Related

Failed to load resource: the server responded with a status of 500 (Internal Server Error) in react

Trying to Post request in react using form but server is responding to 500 error.
The handlesubmit function looks like this, its not working always shows an internal server error with 500 code.
async function handleSubmit(e){
e.preventDefault();
SetBtnText("Sending...");
const response = await fetch("http://localhost/form/contact",
{
mode: 'no-cors',
method :"POST",
headers: {
"Content-Type": "application/json"
},
FormData
})
.then(resp => resp.json())
.then(data => console.log(data));
SetBtnText("Send");
let result = await response.json();
SetFormData(InitialFormData);
if (result.code === 200){
setStatus({ success: true, message: 'Message sent successfully' });
} else{
setStatus({ success: false, message: 'Something went wrong, please try again later.' });
}
}
The Server.js looks like this..
const express = require('express')
const cors = require("cors");
const nodemailer = require("nodemailer");
const router = express.Router();
const dotenv = require('dotenv')
dotenv.config({path:"./.env"})
const app = express();
app.use('/form', router);
app.use(cors());
app.use(express.json());
app.listen(80 , ()=>{console.log("Server Running at Port:80")})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
})
router.post('/contact',(req, res)=>{
const Name = req.body.FirstName + req.body.LastName;
const Email = req.body.Email;
const Message = req.body.Message;
const Phone = req.body.Phone;
const MailOptions = {
from : Email,
to :process.env.EMAIL,
subject: "Contact Form Submission - Portfolio",
html : `<p>Name: ${Name}</p>
<p>Email: ${Email}</p>
<p>Phone: ${Phone}</p>
<p>Message: ${Message}</p>`,
}
console.log(MailOptions)
transporter.sendMail(MailOptions, function(error){
if (error) {
res.json(error)
} else {
res.json({code:200 , msg : "Sent Successfully"})
}
});
});
What should I do to make this work. Please suggest how do I remove this internal server error
From your code I can see you are missing the server port in the react side
it should be http://localhost:80/form/contact NOT http://localhost/form/contact also on the server you are already using cors no need to set no-cors on the client the code will work
for a little tip
use Postman to always test your APIs before integrating it on the client side that way you can be sure the problem is not from the server and if it is fix it before trying it out on the client side

How to deploy React frontend and Node backend into production? (NOT Heroku)

I want to deploy an app which has a contact form that uses Nodemailer to send emails once the form was submitted. The frontend is in React and after submitting it sends an axios request to the backend which is in Node. While on localhost it works perfectly. Also, I've been successful in deploying the entire app to Heroku(frontend and backend) however I want to deploy this app(or rather website) to a normal hosting account with my domain name. Is it possible? Thank you in advance!
Here is my backend server in app.js.
const express = require("express")
const app = express()
const PORT = process.env.PORT || 5000
require("dotenv/config")
const cors = require("cors")
const nodemailer = require("nodemailer")
app.listen(PORT, () => {
console.log("Server running on port: " + PORT);
})
app.use(express.urlencoded({extended:true}))
app.use(express.json())
app.use(cors())
app.get("/", (req,res) => {
console.log("app is working");
})
app.post("/", async (req,res) => {
console.log(("Form submittet"));
console.log(req.body);
const {imeiprezime,predmet,poruka} = req.body
try {
const pitanje = [imeiprezime,predmet,poruka]
console.log(pitanje);
await res.status(201).json({pitanje})
let transporter = nodemailer.createTransport({
host: "smtp-mail.outlook.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "mislav0508#hotmail.com",
pass: process.env.EMAIL_PASS,
},
tls: {
rejectUnauthorized:false
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Mislav Crnkovic" <mislav0508#hotmail.com>', // sender address
to: `mislav0508#hotmail.com`, // list of receivers
subject: `Contact form: ${predmet}`,
html: `
<p>Ime i prezime: ${imeiprezime}</p>
<p>Predmet: ${predmet}</p>
<p>Poruka: ${poruka}</p>
`, // html body
});
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
} catch (error) {
res.status(400)
console.log(error)
}
})
Here is my frontend function in React:
const handleSubmit = async (e) => {
e.preventDefault()
if(data.imeiprezime && data.predmet && data.poruka){
await axios.post("http://localhost:5000/", data) //change URI when deploying app.
.then((result) => {
const pitanje = result.data.pitanje
console.log(pitanje);
alert("Hvala vam na upitu!")
})
.catch(err => console.log(err))
setData({imeiprezime:"",predmet:"",poruka:""})
}else{
console.log("please fill out required fields");
alert("Molimo popunite sva polja")
}
}

ReferenceError: transporter is not defined

i am new in react js am getting an error when i am trying to run my node js server
the error is mentioned in my title box please try to fix it as soon as possible.
index.js
this is my index.js file where i wrote my all backend code
let express = require('express');
let app = express();
const path = require('path');
let nodemailer = require('nodemailer');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
nodemailer.createTransport({
service: 'gmail',
auth: {
user: "harsalpatil512#gmail.com",
pass: "*********"
}
});
// verifying the connection configuration
transporter.verify(function(error, success) {
if (error) {
console.log(error);
} else {
console.log("Server is ready to take our messages!");
}
});
router.post('/access', (req, res, next) => {
var name = req.body.name
var email = req.body.email
var message = req.body.message
var content = ` name: ${name} \n email: ${email} \n message: ${message} `
var mail = {
from: "harsalpatil512#gmail.com",
to: "ashishnirvikar5670#gmail.com",
message: "Welcome to Gmail",
text: "Thanks for contacting us"
}
transporter.sendMail(mail, (err, data) => {
if (err) {
res.json({
status: 'fail'
})
} else {
res.json({
status: 'success'
})
}
})
})
const PORT = process.env.PORT || 8080
app.listen(PORT, () => console.info(`server has started on ${PORT}`))
you need to make a little change:
// need to declare transporter first
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: "harsalpatil512#gmail.com",
pass: "*********"
}
});

ERR EMPTY RESPONSE

I am trying to add a contact form that will send to a dedicated gmail account. I have got the contact form working independently but when I try and add it to my working project it does not work and the error I get is:
Cannot POST /api/send
The project is a MERN stack. Below is the mailer.js middleware:
import nodemailer from 'nodemailer'
import config from '../config'
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
auth: {
user: process.env.username,
pass: process.env.password,
}
});
const send = ({ email, name, text }) => {
const from = name && email ? `${name} <${email}>` : `${name || email}`
const message = {
from,
to: 'react.nodemailer#gmail.com',
subject: `New message from ${from} at creating-contact-forms-with-nodemailer-and-react`,
text,
replyTo: from
};
return new Promise((resolve, reject) => {
transporter.sendMail(message, (error, info) =>
error ? reject(error) : resolve(info)
)
})
}
export default send
The server.js on the backend is:
const express = require('express');
const connectDB = require('./config/db');
const path = require('path');
// // ********************
// // CONTACT FORM
// // ********************
const cors = require ("cors")
const nodemailer = require("nodemailer")
// // ********************
// // CONTACT FORM
// // ********************
const app = express();
// // Connect Database
connectDB();
// Init Middleware
app.use(express.json());
// // ********************
// // CONTACT FORM
// // ********************
app.use(cors());
app.post('/contact', (req, res) => {
const { email = '', name = '', message = '' } = req.body
mailer({ email, name, text: message }).then(() => {
console.log(`Sent the message "${message}" from <${name}> ${email}.`);
res.redirect('/#success');
}).catch((error) => {
console.log(`Failed to send the message "${message}" from <${name}> ${email} with the error ${error && error.message}`);
res.redirect('/#error');
})
})
// // ********************
// // CONTACT FORM
// // ********************
// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/send', require('./routes/api/send'));
// Serve static assets in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
The contact form is:
import React, { Component } from "react";
import axios from "axios";
class ContactForm extends Component {
constructor() {
super();
this.state = {
name: "",
email: "",
message: "",
status: "Submit"
};
}
handleSubmit(event) {
event.preventDefault();
this.setState({ status: "Sending" });
axios({
method: "POST",
url: "api/send",
data: this.state,
}).then((response) => {
if (response.data.status === "sent") {
alert("Message Sent");
this.setState({ name: "", email: "", message: "", status: "Submit" });
} else if (response.data.status === "failed") {
alert("Message Failed");
}
});
}
handleChange(event) {
const field = event.target.id;
if (field === "name") {
this.setState({ name: event.target.value });
} else if (field === "email") {
this.setState({ email: event.target.value });
} else if (field === "message") {
this.setState({ message: event.target.value });
}
}
This is the api POST route.
var express = require('express');
var config = require('config');
var router = express.Router();
var cors = require('cors');
// #route POST api/send
// #desc Send email on contact page
// #access Public
router.post('/api/send',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
I have been trying to debug this for a week or so. I am currently trying to find out why the POST route is not working.
The error codes I have got are 500 internal server error and 404 not found. The url it will be going to is http://localhost:5000/api/send
Change
router.post('/api/send',(req, res, next )
to
router.post('/',(req, res, next )
In your express app your already have.
app.use('/api/send', require('./routes/api/send'));
Thus, for all "/api/send" we will look in the file './routes/api/send'.
The way you defined it you will have to query it like http://localhost:5000/api/send/api/send.
You will have
router.post('/',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
Also how about moving routes to its own file. i.e in server have
app.use(require('./routes/api'));
And in ./routes/api/index.js have the definitions there. i.e
const express = require('express');
const router = express.Router();
router.use('/api/send', require('./send'));
module.exports = router;
You can directly register the route on the express app like below,
app.post('/api/send',function(){
//..send code
//nodemailer.send("blabla")
});
instead of registering routes both on app and router.

Send route not being found,

I am trying to use nodemailer to send an email from the contact page. I have built the site with a MERN stack. All the other routes work perfectly fine. I can setup a new user, write a post and login an existing user. The only part where the routes break is when the mail is sent on the contact page.
Below is the middleware:
const app = express();
// Connect Database
connectDB();
// Init Middleware
app.use(express.json());
// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/send', require('./routes/api/send'));
Below is the send route:
var express = require('express');
var config = require('config');
var router = express.Router();
var nodemailer = require('nodemailer');
var cors = require('cors');
// #route POST api/send
// #desc Send email on contact page
// #access Public
router.post('/send',(req, res ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var mail = {
from: name,
to: receiver, // receiver email,
subject: subject,
text: content
}
transporter.sendMail(mail, (err, data) => {
if (err) {
res.json({
status: 'fail'
})
} else {
res.json({
status: 'success'
})
}
})
});
module.exports = router;
I get a 404 error when I submit the form on contact page. Below is the contact page:
const ContactForm = () => {
const [state, setState] = useState({
name: '',
email: '',
subject: '',
message: ''
});
const [result, setResult] = useState(null);
const sendEmail = event => {
event.preventDefault();
axios
.post('/send', { ...state })
.then(response => {
setResult(response.data);
setState({
name: '',
email: '',
subject: '',
message: ''
});
})
.catch(() => {
setResult({
success: false,
message: 'Something went wrong. Try again later'
});
});
};
const onInputChange = event => {
const { name, value } = event.target;
setState({
...state,
[name]: value
});
};
This is my handler:
const nodemailer = require ('nodemailer');
nodemailer.createTransport({
host: "smtp.gmail.com", //replace with your email provider
port: 587,
auth: {
user: process.env.email,
pass: process.env.password
}
});
// verify connection configuration
transporter.verify(function(error, success) {
if (error) {
console.log("error at mail send");
} else {
console.log("Server is ready to take the messages");
}
});
module.exports = transporter
To debug I have tried to change the POST route to
(req, res, next)
(req, res, send)
It seems like you missing transpoter object.
You need to create it with nodemailer.createTranspot
const transpoter = nodemailer.createTranspot({
service: 'gmail',
auth: {
user: 'sender#gmail.com',
pass: 'password'
}
})
then try it.
This has been solved by:
Moving the transporter to the send route
The route that the server is using was api/send/send on the POST route it should be /

Resources