Simple email sender with NodeJS and Express - node.js

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

Related

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.

Form works fine on localhost but throws 404 once deployed

The solution seems to be in front of eyes, but everything I tried so far didn't work. I'm using nodemailer to send e-mail through a form and it works fine on local host but when I deploy it, it doesn't work. I think it has something to do with the routing but I can't figure it out. What should I have on "action" and "app.post"? I'm using a subdomain on inmotion to test the form.
const nodemailer = require ('nodemailer')
const express = require ('express')
const bodyParser = require ('body-parser')
const app = express()
app.use (express.static('./public'))
app.use (bodyParser.json())
app.use (bodyParser.urlencoded ({extended: true}))
const transporter = nodemailer.createTransport({
host: "biz260.inmotionhosting.com",
port: "465",
secure: true,
auth: {
user: "test#learningtodom.com",
pass: "xxxxxx"
}
})
function sendEmail(mail) {
var mailOptions = {
from: "test#learningtodom.com",
to: "pablo.football.coach#gmail.com",
subject: "Mail",
html: mail.body
}
transporter.sendMail (mailOptions, function (err, info){
if (err) {
console.log (err)
}
else {
console.log('Done' + info.response)
}
})
}
app.post ('/send_email_form', (req, res) => {
mail = {
to : req.body.name,
subject: req.body.second,
body: req.body.second
}
sendEmail(mail)
res.redirect ('/')
})
app.listen (8100, () => {
console.log ('Server Running at 8100')
})
Form
<form action="/send_email_form" method="POST">
<div class="form-row">
<div class="col-md-4 mb-3">
<label for="validationServer01">First name</label>
<input type="text" name ="name" class="form-control is-valid" id="validationServer01" placeholder="First name" value="Mark" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
It may be your port settings, 8100 is not a normal port to be open on a production server. It is most common to see regular HTTP traffic on port 80, and HTTPS traffic on port 443.
If it is possible to open port 8100 on your remote server, you should do that to check if your server is reachable on that port. It can help to add a simple status checking endpoint such as
app.get ('/status', (req, res) => {
res.json({ status: 'ok' })
})
and then confirm that you can access that by trying http://[yourdomain]:8100/status in a browser.
I highly recommend reading your port number from your environment variables (like node.env.PORT) so that you can easily serve locally on 8100 but then switch to 80 and/or 443 when deployed on a remote server.
Once you confirm that you can hit a GET/status route, then any other issue you have will be to do with your nodemailer setup.
Also, be aware that using a library like nodemailer may make your mail likely to go into your spam folder. Paid services like Sendgrid and Mailgun work hard to ensure the authenticity of email senders, so emails sent using them are much more likely to be delivered as not spam.
If you are going to be the only recipient of this mail, and can find it in your spam folder, make sure to mark it as not spam, and try to let your inbox know that you trust emails from this address.
Good luck, hope this helps :)

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.
}

Nodemailer /send gives 404 error

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!

How to use firebase authentication in Node.js application?

I tried to implement the firebase authentication in my Node + Express application. But can not figure out how to authenticate an user using email and password. It would be helpful if there is a tutorial or example project.
I know this might help someone in need of help like Shams Nahid, there is firebase authentication tutorial that i would recommend for this. Firebase Authentication Tutorial using
To implement user login using firebase, Node js and express, follow these simple steps
Step 1. Follow this documentation about firebase authentication How to use email and password to sign in
Step 2. Create a login.ejs file
<!doctype html>
<html>
<head> <title>Login into your account</title>
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-app.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-auth.js"</script>
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-firestore.js"
</script>
<script src="https://www.gstatic.com/firebasejs/6.1.0/firebase-database.js">
</script>
<link rel="stylesheet"
href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-
awesome/4.0.3/css/font-awesome.min.css">
<style>body{padding-top:80px;}</style>
</head>
<body>
<div class="container " >
<div class="col-sm-6 col-sm-offset-3 ">
<h1><span class="fa fa-sign-in"></span> Login</h1>
<!-- LOGIN FORM -->
<fieldset>
<div class="form-group">
<label>Email</label>
<input type="email" id="txtemail" value="" class="form-control">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" id="txtpassword" value="" class="form-
control">
</div>
<button type="submit" id="loginButton" onclick="signInUsers()"class="btn
btn-warning">Login
</button>
<button type="submit" id="logoutButton" onclick="logout()"class="btn btn-
warning">logout</button>
</fieldset>
<hr>
</div>
</div>
<script src="/js/firebase.js"></script>
</body>
</html>
Step 3. create an authentication script
firebase.js
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "INSERT HERE YOUR API FROM FIREBASE CONSOLE",
authDomain: "INSERT YOUR DOMAIN",
databaseURL: "INSERT YOUR DATABASE URL",
projectId: "INSERT HERE YOUR PROJECT ID",
storageBucket: "canon-4f6d8.appspot.com",
messagingSenderId: "INSERT HERE YOUR MESSAGING ID FROM FIREBASE",
appId: "1YOUR APP ID FROM FIREBASE"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
function signInUsers(){
var email = document.getElementById('txtemail').value;
var pass = document.getElementById('txtpassword').value;
firebase.auth().signInWithEmailAndPassword(email, pass)
.catch(function(error) {
// Handle Errors here.
let errorCode = error.code;
let errorMessage = error.MESSAGE;
console.log(errorCode);
console.log(errorMessage);
});
}
//check if user is logged in or not
function checkIfLogedIn(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) { // if the user is logged in
console.log(user)
var emailv =user.email;
console.log("User is signed in. with email: "+ emailv);
document.getElementById('loginButton').setAttribute('style','display: none;visibility: hidden;');
document.getElementById('logoutButton').setAttribute('style','display: inline-block;visibility: visible;')
} else { // if the user is not logged in
console.log("No user is signed in.");
document.getElementById('loginButton').setAttribute('style','display: none;visibility: visible;');
document.getElementById('logoutButton').setAttribute('style','display: inline-block;visibility: hidden;')
}
});
}
window.onload=function(){
checkIfLogedIn()
}
function logout(){
firebase.auth().signOut();
checkIfLogedIn()
}
Step 3. Create your app.js script that you will be running
app.js file
var express=require('express')
var logger=require('morgan')
var passport = require('passport');
var bodyParser=require('body-parser')
var admin=require('firebase-admin')
var path = require('path');
var serviceAccount=require('./canon-serviceKey.json')
var firebaseAdmin=admin.initializeApp({
credential:admin.credential.cert(serviceAccount),
databaseURL: "INSERT YOUR FIREBASE DB URL"
})
///database reference
var database=firebaseAdmin.database()
//create instance of express app
var app=express()
//we want to serve js and html in ejs
//ejs stands for embedded javascript
app.set('view engine','ejs')
//we also want to send css images and other static files in views folder
//app.use(express.static('views'))
app.use(express.static(path.join(__dirname, '/views/')));
app.set('views',__dirname+'/views/')
//Give the server access to user input
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended:false}))
app.use(logger('dev'))
//create authentication middle ware
function checkLoggedIn(request, resposense, next) {// if user is authenticated in the session, carry on
if (request.isAuthenticated())
return next();// if they aren't redirect them to the index page
resposense.redirect('/');
}
app.get('/',function(request,response){
response.render('login.ejs')
})
app.get('/login', function(request,response){
response.render('profile.ejs')
});
app.get('/logout', function(request,response){
response.render('login.ejs')
});
app.listen(port,function(){
console.log('App running on port'+port)
})
NOTE: Make sure you install the necessary packages first using npm install package-name
such as
express
morgan
firebase-admin
body-parser
After doing the above steps you run your app.js using node app.js and you will be good to go.
i hope this helps some one with the same issue about firebase authentication using node js and express

Resources