Nodemailer /send gives 404 error - node.js

I'm trying to use nodemailer to send a message from a standard website form to an email address. I have followed this tutorial and everything works on the local server. But when I upload the documentation to my hosting provider I get the following error:
POST http://mydomain.rs/send 404 (Not Found)
Not Found
The requested URL /send was not found on this server.
Additionally, a 404 Not Found error was encountered while trying to use an
ErrorDocument to handle the request.
I have three files relevant to the nodemailer, those are:
app.js
var http = require('http');
var express = require('express');
var nodemailer = require("nodemailer");
var bodyParser = require('body-parser');
var path = require('path');
var app = express();
var port = Number(process.env.PORT || 5000);
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static(__dirname + '/'));
// Home page
app.get('/', function (req, res) {
res.sendFile('index.html');
//console.log
console.log('NodeMailer reading console log...' + req.url);
});
// sending mail function
app.post('/send', function (req, res) {
if (req.body.email == "" || req.body.subject == "") {
res.send("Error: Email & Subject should not blank");
return false;
}
// Sending Emails with SMTP, Configuring SMTP settings
var smtpTransport = nodemailer.createTransport("SMTP", {
host: "mail.mydomain.rs", // hostname
secureConnection: true, // use SSL
port: 465, // port for secure SMTP
auth: {
user: 'messages#mydomain.rs',
pass: 'password'
},
proxy: 'http://mydomain.rs:' + port
});
var mailOptions = {
from: "Node Emailer ✔ <messages#mydomain.rs>", // sender address
to: req.body.emailto, // list of receivers
subject: req.body.subject + " ✔", // Subject line
//text: "Hello world ✔", // plaintext body
html: "<b>" + req.body.description + "</b>" // html body
}
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
res.send("Email could not sent due to error: " + error);
} else {
res.send("Email has been sent successfully");
}
});
});
// Starting server
var server = http.createServer(app).listen(port, function () {
console.log("Server is Running on 127.0.0.1:" + port);
});
the part of the index page relevant to the form:
index.html
<form role="form" id="emailForm" method="post">
<div class="form_content">
<h2>KONTAKTIRAJTE NAS</h2>
<p id="msg"></p>
<input type="text" name="ime" placeholder="IME" required="required" />
<input type="tel" name="telefon" placeholder="TELEFON" />
<p class="mini_text">
Otvoreni od 8h - 17h
<br> Zatvoreni vikendom osim za posebne usluge
</p>
<input type="email" name="emailto" value="myactualemail#gmail.com" style="visibility: hidden; position: absolute;">
<input type="email" name="email" placeholder="EMAIL" required="required" />
<textarea name="description" placeholder="PORUKA" required="required"></textarea>
<button id="send" type="button">POŠALJI</button>
</div>
</form>
and the package.json
{
"name": "speednodemailers",
"version": "0.0.1",
"description": "NodeJs email form to send email using nodejs",
"dependencies": {
"body-parser": "^1.13.3",
"express": "^3.21.2",
"node-mailer": "^0.1.1",
"nodemailer": "^0.7.1"
}
}
So as I mentioned everything works perfectly on localhost, the problem occurs when I upload the project to my hosting provider.
Is there a step to the upload that I am missing?
Or a setting that I overlooked?
Any kind of help will be greatly appreciated as I am somewhat of a beginner at back-end stuff.
Thanks!

Related

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.

Contact Form Vulnerability, Reveals Email Password

I put a contact form on my personal portfolio website, and every couple of weeks, the email address associated with the contact form (which is used nowhere else) gets compromised. Through some means that I'm not aware of, someone is able to gain access to the password (which is used nowhere else) and attempts to log in to my account with it.
When the account is compromised, I find I have three emails from seemingly random addresses with seemingly random, single-word subjects and content.
All passwords are over 10 characters long, using capitals, lowercase, numbers, and symbols.
The website is static, hosted on Netlify. The email is handled by a Node.js microservice hosted on Heroku. Here's my contact form.
<form id="contact-form" autocomplete="off">
<label for="name">Name</label>
<input type="text" id="name" name="name" value="" required />
<label for="email">Email</label>
<input type="email" id="email" name="email" value="" required />
<label for="subject">Subject</label>
<input type="text" id="subject" name="subject" value="" required />
<label for="text">Message</label>
<textarea id="text" name="text" value="" required></textarea>
<button type="submit">Submit</button>
</form>
Here's the code that handles the contact form:
$("#contact-form").submit((e) => {
e.preventDefault();
$.ajax({
url: "https://my-microservice.herokuapp.com/email",
type: "POST",
dataType: "json",
data: $("#contact-form").serialize(),
success: function (response) {
$("#contact-form").html(
"<div class='form-success'><h2>Your message has been sent! Thanks for getting in touch.</h2></div>"
);
},
error: function (xhr, status, error) {
$("#contact-form").html(
"<div class='form-failure'><h2>Uh-oh! Something went horribly wrong. You can email me directly at <a href='mailto: anotheremailaddress#gmail.com'>anotheremailaddress#gmail.com</a></h2></div>"
);
},
});
});
Here's the microservice that handles the email:
require("dotenv").config();
const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
var corsOptions = {
origin: "https://www.my-portfolio-site.com",
optionsSuccessStatus: 200
};
app.use(
bodyParser.urlencoded({
extended: true
})
);
var transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
app.post("/email", cors(corsOptions), (req, res) => {
var mailOptions = {
from: "my-portfolio-site.com",
to: process.env.EMAIL,
subject: "PORTFOLIO MESSAGE",
text: `from: ${req.body.email}\nsubject: ${req.body.subject}\nmessage:\n\n${req.body.text}`
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
res.send(error);
} else {
console.log("Email sent: " + info.response);
res.send(info);
}
});
});
let port = process.env.PORT;
if (port == null || port == "") {
port = 8000;
}
const listener = app.listen(port, function() {
console.log("Your app is listening on port " + listener.address().port);
});
Any insight into how my password might be being compromised and how I might stop it would be very much appreciated. Thanks for your time.
on the microservice there is a piece of code that allows CSRF attack thi is the part:
app.use(
bodyParser.urlencoded({
extended: true
})
);
for more details you can take a look here or search on google what that extended : true means.

Firebase Functions HTTPS 403 Forbidden

I built a Firebase HTTP Event function with Node and Express. The function is working, but when I invoke the function on the client side I get 403 Forbidden. The first time I invoked the function I was asked to sign in with a Google account. I signed in with the same account I use for Firebase, but when I invoked the function I got:
Screenshot of 403 error
I looked at the use roles on Google cloud platform and the permission to invoke the function is set to allUsers. I signed out and back in again in the Firebase CLI.
Here is the index.js in the functions folder:
const functions = require('firebase-functions');
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const port = process.env.port || 5600
const nodemailer = require('nodemailer');
app.use(express.static('Public'));
app.use(bodyParser.urlencoded({ extended: true }));
const urlencodedParser = bodyParser.urlencoded({extended: true});
app.post("/api/user", urlencodedParser, (req, res) => {
res.sendFile('../Public/bedankt.html', {root: __dirname})
const persGegevens = req.body
const string = JSON.stringify(persGegevens, (key, value) => {
if (typeof value === "string"){
return value.toUpperCase();
} else {
return value
}
}, 1);
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'gietvloermakers#gmail.com',
pass: 'Gietvloermakers2020!'
}
});
var mailOptions = {
from: 'gietvloermakers#gmail.com',
to: 'gvbeusekom84#hotmail.com',
subject: 'Nieuwe bestelling op Gietvloermakers',
html: string
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
});
exports.app1 = functions.https.onRequest(app);
app.listen(port);
console.log(port);
Here is the html:
<form id="controlleer-form" action="/api/user" method="post" enctype="application/x-www-form-urlencoded">
<div class="controleer-div">
<h2>Uw bestelling</h2>
<p>Aantal m2</p>
<input class="controle-input" type="text" name="aantalM2" id="aantalM2" readonly>
<p>Kleur</p>
<input class="controle-input" type="text" name="kleur" id="kleur" readonly>
<p>Assistentie</p>
<input class="controle-input" type="text" name="assistentie" id="assistentie" readonly>
<p>Gereedschappen</p>
<input class="controle-input" type="text" name="gereedschappen" id="gereedschappen" readonly>
<p>Totale prijs</p>
<input class="controle-input" type="text" name="totale-prijs" id="totale-prijs" readonly>
<p id="andere-kleur">Bestelling aanpassen</p>
</div>
<div class="controleer-div">
<h2>Uw gegevens</h2>
<p>Voornaam</p>
<input type="text" name="voornaam" placeholder="Voornaam">
<p>Achternaam</p>
<input type="text" name="Achternaam" placeholder="Achternaam">
<p>Straatnaam en huisnummer</p>
<input type="text" name="Achternaam" placeholder="Straatnaam en huisnummer">
<p>Postcode</p>
<input type="text" name="Achternaam" placeholder="Postcode">
<p>Telefoonnummer</p>
<input type="tel" name="telefoonnummer" placeholder="Telefoonnummer">
<p>Emailadres</p>
<input type="email" name="email" placeholder="Emailadres"><br>
<input id="verzenden" type="submit">
</div>
</form>
Here is the firebase.json:
{
"hosting": {
"public": "Public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "**",
"function": "app1"
}]
}
}
I tried but I exhausted all possible solutions I've found online so far.
I encountered this recently. It turns out that as of January 15, 2020 new functions require authentication by default.
See the docs here for details.
The solution was to manually add the Cloud Functions Invoker permission to the allUsers user in the Cloud Functions page in the Google Cloud Console.
If you are getting 403 forbidden error like below
Error: Forbidden Your client does not have permission to get URL
/api/test from this server.
Please follow below steps to grant access to all users. Basically this is to allow unauthenticated clients to access your api endpoint.
Go to https://console.cloud.google.com/functions/list
Select the function to which you want to give public access
Click on PERMISSIONS
Click on ADD MEMBER
Type allUsers
Select role Cloud Functions -> Cloud Functions Invoker
Save
That's it, now test your api.
This has to do with permission access to your cloud functions http requests and cloud function events, you need to edit your cloud function IAM permission.
https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation
Had the same problem (was asked to login with my Google Account, then denied access). It turned out that functions do currently not work outside the default region. In my case, I had to make a change here:
exports.app = functions
.region('europe-west6') // does not work, delete this line
.https.onRequest(app);
Your code exports the express application as the Cloud Function app1 on this line:
exports.app1 = functions.https.onRequest(app);
In your screenshot, you have tried to access the non-existent app Cloud Function instead resulting in the 403 Forbidden response.
This means the correct URL to call from your client is
http://us-central1-gietvloermakers.cloudfunctions.net/app1/api/user
^^^^
(or you could change the name of the export to app)
Having a closer look at your source code, you should also remove the following lines. If you wanted to test your code you would instead use firebase serve.
const port = process.env.port || 5600
/* ... */
app.listen(port);
On the following lines, you also inject the body parser twice.
app.use(bodyParser.urlencoded({ extended: true })); // use this
const urlencodedParser = bodyParser.urlencoded({extended: true}); // or this, not both
app.post("/api/user", urlencodedParser, ...
In your code, you also have:
app.post("/api/user", urlencodedParser, (req, res) => {
res.sendFile('../Public/bedankt.html', {root: __dirname})
/* do some other stuff */
})
This is invalid for a Cloud Function, because as soon as the Cloud Function handler (your code) calls end(), redirect() or send(), the Cloud Function is allowed to be terminated at any time which means that your email may never be sent. To fix this you need to send the file last.
app.post("/api/user", urlencodedParser, (req, res) => {
/* do some other stuff */
res.sendFile('../Public/bedankt.html', {root: __dirname})
});
My last observation, is that the error may be caused by the folder Public not existing on the server. Based on your sendFile call, you are expecting that the folder "Public" is available to your deployed function but as it is not inside the functions folder, it will not be deployed with your code.
res.sendFile('../Public/bedankt.html', {root: __dirname})
As this file would also be accessible at your-domain.com/bedankt.html, we'll redirect to it. If you wanted to send the HTML content of this file instead, move it inside your deployed functions directory.
res.redirect('/bedankt.html')
Because you appear to be trying to use your express function behind Firebase hosting, we can trim your index.js file to the following:
const functions = require('firebase-functions');
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const apiApp = express();
apiApp.use(bodyParser.urlencoded({ extended: true }));
apiApp.post("/api/user", (req, res) => {
const persGegevens = req.body
const string = JSON.stringify(persGegevens, (key, value) => {
if (typeof value === "string"){
return value.toUpperCase();
} else {
return value
}
}, 1);
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'gietvloermakers#gmail.com',
pass: 'Gietvloermakers2020!'
}
});
var mailOptions = {
from: 'gietvloermakers#gmail.com',
to: 'gvbeusekom84#hotmail.com',
subject: 'Nieuwe bestelling op Gietvloermakers',
html: string
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
res.redirect('/bedankt.html?success=0');
} else {
console.log('Email sent: ' + info.response);
res.redirect('/bedankt.html?success=1');
}
});
});
// note rename to api
exports.api = functions.https.onRequest(apiApp);
which requires updating your firebase.json file to:
{
"hosting": {
"public": "Public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/api/**",
"function": "api"
}]
}
}
This configuration will first attempt to find a matching file in your Public directory. If it can't find a match, it will check if the requested path starts with /api and if so, launch your Cloud Function. If it still can't find a match, it will show your 404 page (or the built in one if it doesn't exist).

Sending email to several recipients via nodemailer doesn't work

I tried looking for different answers but they didn't work. I don't receive the email in my gmail account when I am trying to send it, I am just getting it in my Ethereal account.
This is my server code:
const express = require('express');
const path = require('path');
const cons = require('consolidate');
const bodyParser = require('body-parser');
const nodemailer = require("nodemailer");
const app = express();
app.engine('html', cons.swig)
app.set('../public', path.join(__dirname, 'public'));
app.use('../src/css', express.static(path.join(__dirname, 'src/css')));
app.use('../src/js', express.static(path.join(__dirname, 'src/js')));
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());
app.post('/send',(req,res) => {
const output = `
<p>name of client: ${req.body.name}</p>
`;
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false,
auth: {
user: "*****#ethereal.email",
pass: "********"
},
tls: {
rejectUnauthorized: false
}
});
let mailOptions = {
from: `${req.body.email}`,
to: "******#gmail.com",
subject: "Node contact request",
text: "Hello world?",
html: output
};
transporter.sendMail(mailOptions, (error, info) => {
if(error) {
return console.log(error);
}
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
res.render('index')
});
});
app.listen(5000);
I am using react app for my front-end(e-commerce), and I want that after sending the email the client will see a message saying "The email has been sent" (the location doesn't really matter for now). How can I do it after submitting the form? Right now the client is directing to localhost:5000/send instead of staying at the same page.
This is my react code:
import React from 'react';
const contact = () => {
return (
<form className="contact" action="http://localhost:5000/send" method="post">
<div className="contact-topFields">
<div className="contact-topFields-email">
<input
className="contact-topFields-email-input"
type="email"
name="email"
required/>
<ion-icon id="email-icon" name="mail"></ion-icon>
<p className="contact-topFields-email-text">Email</p>
</div>
<div className="contact-topFields-name">
<input
className="contact-topFields-name-input"
type="text"
name="name"
required/>
<ion-icon id="name-icon" name="person"></ion-icon>
<p className="contact-topFields-name-text">Name</p>
</div>
</div>
<div className="contact-bottomFields">
<div className="contact-bottomFields-phone">
<input
className="contact-bottomFields-phone-input"
type="text"
name="phonenumber"
required/>
<ion-icon id="phone-icon" name="call"></ion-icon>
<p className="contact-topFields-phone-text">phone</p>
</div>
</div>
<div className="contact-text">
<textarea className="contact-text-textarea" name="message" required></textarea>
</div>
<button className="contact-submitButton" type="submit">send </button>
</form>
)
}
export default contact;
To prevent the page being directed to localhost:5000/send:
In order to trigger sending the email while keep the user's view unchanged, you may want to override the form's submit function.
For example, you may want to do this in your JSX code:
<form className="contact" onSubmit={{this.handleSubmit}}>
<- whatever inside form ->
</form>
Then you may want to define a function handleSubmit:
function handleSubmit (evt) {
evt.preventDefault() // this is used to prevent ui from being directed
// Do http request here, use a http agent such as fetch(), axios() etc etc.
}

Simple email sender with NodeJS and Express

I'm totally new to web development and working with web related concepts and frameworks (IPs, networks, routers, I cringe everytime :D ).
But, thanks to some internship work I have "forced myself" to work with this and thanks to lots of digging on the internet I have managed to develop a super simple app that can send emails if I am under my localhost. But, I have some (many) questions, but first, the files that comprise all of my code:
Package.json file
{
"name": "email-node",
"version": "1.0.0",
"dependencies": {
"nodemailer": "~0.7.1",
"express": "~4.5.1"
}
}
Index.html
<html>
<head>
<title>Node.JS Email application</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>// <![CDATA[
$(document).ready(function(){
var from,to,subject,text;
$("#send_email").click(function(){
to=$("#to").val();
subject=$("#subject").val();
text=$("#content").val();
$("#message").text("Sending E-mail...Please wait");
$.get("http://localhost:3000/send",{to:to,subject:subject,text:text},function(data) {
if(data=="sent") {
$("#message").empty().html("Email is been sent at "+to+" . Please check inbox !");
}
});
});
});
</script>
</head>
<body>
<div id="container">
<h1>Mailer In Node.JS</h1>
<input id="to" type="text" placeholder="Enter E-mail ID where you want to send" />
<input id="subject" type="text" placeholder="Write Subject" />
<textarea id="content" cols="40" rows="5" placeholder="Write what you want to send"></textarea>
<button id="send_email">Send Email</button>
<span id="message"></span>
</div>
</body>
</html>
app.js File
var express=require('express');
var nodemailer = require("nodemailer");
var app=express();
/*
Here we are configuring our SMTP Server details.
STMP is mail server which is responsible for sending and recieving email.
*/
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "MYGMAIL#gmail.com",
pass: "MYGMAILPASS"
}
});
/*------------------SMTP Over-----------------------------*/
/*------------------Routing Started ------------------------*/
app.get('/',function(req,res){
res.sendfile('index.html');
});
app.get('/send',function(req,res){
var mailOptions={
to : req.query.to,
subject : req.query.subject,
text : req.query.text
}
console.log(mailOptions);
smtpTransport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
console.log("Message sent: " + response.message);
res.end("sent");
}
});
});
/*--------------------Routing Over----------------------------*/
app.listen(3000,function(){
console.log("Express Started on Port 3000");
});
From what I have read here is what I concluded:
Node.js + Express applications always "listens" to incoming connections on port 3000 so that is the value I use.
Ideally, to send stuff from a website instead of my localhost I believe that the problem lies on the index.html file.
Specifically, this line:
$.get("http://localhost:3000/send",{to:to,subject:subject,text:text},function(data){
where instead of using http://localhost:3000/send I would use something like:
http://bruno-oliveira.github.io:3000/send
I have read countless forums and posts, tried everything from:
$.get("/send",{to:to,subject:subject,text:text},function(data){
to searching for github servers IP adress range ( https://developer.github.com/v3/meta/ ) to try and use them directly there and nothing seems to work...
The application is supposedly host here:
http://bruno-oliveira.github.io/
Can someone help me?
Best,
Bruno

Resources