Nuxt.js and Node.js simple form with nodemailer PROBLEM :( - node.js

I am new to Nuxt.js and Node.js. I would like to run a very simple contact form on a 'contact.vue' page. It works very well locally, but as soon as I do an 'npm run generate' to generate the files and upload all of this to an FTP it doesn't work anymore. I have an error in the console: "POST http://website.com/api/message 404 (Not Found)"
I use the POST method on my form with the action that points to 'api / message'. I am using axios in a method (on this same 'contact.vue' page :
async onSubmit (e) {
e.preventDefault()
await this.$axios.post('/api/message', {
name: this.contactForm.name,
firstname: this.contactForm.firstname,
})
.then((res) => {
// On clear le formulaire
this.contactForm.name = ''
this.contactForm.firstname = ''
})
.catch((err) => {
console.log(err)
})
}
I have in the root folder an 'api/' folder with inside 'index.js' and the code :
const app = require('express')()
const bodyParser = require('body-parser')
const nodemailer = require('nodemailer')
module.exports = { path: '/api', handler: app }
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.post('/message', async (req, res) => {
const contenuFormulaireContact = `
<ul>
<li>Nom : ${req.body.name}</li>
<li>Prénom : ${req.body.firstname}</li>
</ul>
`
// NODEMAILER
const transporter = nodemailer.createTransport({
host: '',
port: 465,
secure: true,
auth: {
user: '',
pass: ''
}
})
const info = await transporter.sendMail({
from: '"Website's Name" <hello#website.com>', // sender address
to: 'myemail#website.com', // list of receivers
subject: `NEW MESSAGE : ${req.body.subject}`, // Subject line
text: '', // plain text body
html: contenuFormulaireContact // html body
})
console.log('Message sent: %s', info.messageId)
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
res.redirect(200, '/contact')
})
Inside the nuxt.config.js i have :
/*
** Nuxt.js modules
*/
modules: [
'#nuxtjs/pwa',
'#nuxtjs/axios'
],
/*
** Axios cfg
*/
axios: {
baseURL: '/'
},
/*
** Server middleware
*/
serverMiddleware: ['~/api/index.js'],
I'm sorry if for some of you this problem may seem very obvious but I'm completely stuck.
Thank you very much in advance if you take the time to help me.

Actually when you run npm run generate, the website becomes fully static and node doesn't run in the background anymore. This is why your code would works with npm run dev or npm run start since they runs node simultaneously.
I am facing the same issue. A static website is not able to send mail from the client. It has to be sent server-side. To make your code works, you either have to use a node.js server, use serverless functions solutions like AWS Lambda or Netlify functions which will executes the mail sender function or use an external REST API service like Formspree or 99inbound.
See https://stackoverflow.com/a/53560851/2610770.
I hope I helped you a bit!

Related

CORS blocking post requests - react and node.js

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

Sending email successfully. But got 503 statuscode. Heroku, NodeJS, Nodemailer

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.

Nodemailer working on Localhost, not on live Netlify site

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

Express backend dropping data when passed from Angular 5 App

I am building a little demo app to send emails from a form using Node Mailer. I've connected an Angular 5 app to an Express 4 backend. I am running things very simply, with a server.js express file in my project referencing the angular dist file. I then build the angular app and run the server.
Everything is working fine, and the email even sends, but somehow the express backend is losing the data (or I am just not accessing it correctly). The email sends with "undefined" everywhere that I try to use data.
I fill out form fields for name, phone, email, and address. Then I pull the data into a service and send it to the backend. This is my service in Angular that sends the data:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class ClientService {
headers: any;
clientInfo = '';
constructor(private http: HttpClient) { }
sendEmail(clientData) {
console.log(clientData);
return this.http.post('/send-email', clientData);
}
}
When I send this http post it looks good. The request url is correct, the header is application/json, and the payload data is correct: {name: "John Doe", email: "john#johndoemail.com", phone: "18005555555", message: "test"}
Here is my server.js: (sub in a valid gmail account info where there are x's)
// Get dependencies
const express = require('express');
const nodemailer = require("nodemailer");
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
const app = express();
const port = 4300;
// Start server
app.listen(port, function(req, res) {
console.log('Server is running at port: ', port);
})
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Home route to serve the index file
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/send-email', function (req, res) {
console.log(req.body);
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user:'xxxxxx#gmail.com',
pass: 'xxxxxxxx',
}
});
let message = {
from: 'mailer#nodemailer.com',
to: 'xxxxx#gmail.com',
subject: 'New Client Message ' + req.body.name,
text: 'Name: ' + req.body.name + '\nEmail: ' + req.body.email + '\nPhone: ' + req.body.phone + '\n ' + req.body.message,
html: '<p>' + req.body.message + '</p>'
};
transporter.sendMail(message);
res.json(req.body);
});
In the server console req.body shows up as "{}".
Using my own email, I get a message sent from nodemailer, but all of the data used simply says "undefined".
Do I need to access the data differently? Maybe use another property of req? Anyway, it looks like the issue is in my express file, so let me know if you see any issues there.
I found the solution. I was not implementing a header with my post data. I added these changes to my service and the issue was resolved:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable()
export class ClientService {
httpHeader = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
constructor(private http: HttpClient) { }
sendEmail(clientData) {
console.log(clientData);
this.http.post('/send-email', clientData, this.httpHeader);
}
}
If you want to see the full demo look here: https://github.com/xTumulus/NodeMailer_AngularExpress_Demo

401 Error with post request Stormpath Express + React + Node + Gulp

When attempting to login any user, the following POST error results:
XMLHttpRequest cannot load https://api.stormpath.com/v1/applications/[APP_HREF]/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 401.
In my server.js file, I have put the following:
var express = require('express');
var stormpath = require('express-stormpath');
var cors = require('cors');
var app = express();
app.use(stormpath.init(app, {
apiKey: {
id: 'xyz',
secret: 'abc' // Using the unsafe inline option for example purposes
},
application: {
href: `[APP_HREF]`
},
web: {
produces: ['application/json']
},
debug: 'info'
}));
app.use(cors({
origin: 'http://localhost:8080',
credentials: true
}));
app.post('/', stormpath.loginRequired, function (req, res) {
function writeError(message) {
res.status(400);
res.json({ message: message, status: 400 });
res.end();
}
});
app.on('stormpath.ready', function () {
var server = app.listen(process.env.PORT, function() {
try {
process.send('CONNECTED');
} catch(e) {}
});
});
In my login.jsx file, I have included:
login: function(e) {
e.preventDefault();
e.stopPropagation();
this.serverRequest = $.post('https://api.stormpath.com/v1/applications/[APP_HREF]/login',
{
"username": document.getElementById("email").value,
"password": document.getElementById("pass").value
}, function (result) {
console.log(result);
});
I also have saved my stormpath.yml file.
I'm not using React-Stormpath because I already created my views for Login and Registering. It looks like I only need to access the REST api with Stormpath, but I'm not sure what I need to add in order to get the API key validated.
On the actual login.jsx file, would I have to send the ID:SECRET pair as well as part of the POST request?
I see that in your login.jsx you are trying to post directly to the Stormpath REST API, but unfortunately that isn't possible yet. Instead you will make the post to your Express server, and in turn it will communicate with Stormpath.
You already have express-stormpath in your Express server, so you just need to post your login form to /login and Stormpath will take care of the rest :)
Let us know if you run into any issues! FYI, we will be adding a "serverless" feature soon, you can follow that here: http://ideas.stormpath.com/ideas/IAM-I-59

Resources