Error when sending emails using Nodemailer - html

server.js:
app.post('/game',(req,res,next)=>{
//if(!emailValidator(req.body.email)){
// I would do email validations client side to but if you
// want to do server side send some html saying the email is invalid
//res.sendFile(invalidEmail.html)
//}
//else{
//I assume you have some script for sending email. I'll use nodemailer cuz its the first
//module I found
let sender = 'myemail#gmail.com'
let transporter = nodemailer.createTransport({
service:'gmail',
auth:{
user:sender,
pass:'Mypassword'
}
})
let mailOptions = {
from: sender,
to: req.body.email,
subject:'New sign up',
text:'Thanks for subscribing'
}
transporter.sendMail(mailOptions,function(error,info){
if(error){
// do somehting
console.log(error)
}
else{
console.log('Sent new user email')
req.next()
}
})
}
//}
)
index.html:
<form action="game" method="post" size="30">
<input type="text" name="email"/>
<input type="submit" />
</form>
I'm having this error:
TypeError: Cannot read property 'email' of undefined
So there is this error with my code, I'm trying to send an email with Nodemailer from a form in HTML, can someone help me fix this?
Also there is a part for email validation but I removed it as it says "emailValidator" is undefined.

Inside the main folder, create a public folder, inside it create an index.html file
<!DOCTYPE html>
<html>
<head>
<title>Simple page</title>
</head>
<body>
<form action="game" method="post" size="30">
<input type="text" name="email"/>
<input type="submit" />
</form>
</body>
</html>
Inside the main folder, create a server.js file
const express = require('express')
const app = express()
const path = require('path')
const bodyParser = require('body-parser')
const nodemailer = require('nodemailer')
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/public', express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'))
});
app.post('/game', (req, res) => {
let senderUsername = 'example#gmail.com' // sender email address
let senderPassword = 'password'; // senders password
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: senderUsername,
pass: senderPassword
}
});
const mailOptions = {
from: senderUsername, // sender address
to: req.body.email, // list of receivers
subject: 'New sign up', // Subject line
html: '<p>Thanks for subscribing.</p>'// plain text body
};
transporter.sendMail(mailOptions, function (err, info) {
if(err)
console.log(err)
else {
console.log('Sent new user email')
console.log(info);
req.next()
}
});
})
const PORT = 5000;
app.listen(PORT, ()=>{
console.log(`server running on PORT ${PORT}`)
})
Note :
You may also need to follow these steps while using a google account.
Enable the settings to allow less secure apps for the Gmail account that you are using.
Here is the link: Google less secure apps
Allow access for "Display Unlock captcha option" (Allow access to your Google account)
Here is the link: Google unlock captcha
You can also explore MailJet or SendGrid for sending emails.

Related

Pass the values from a post method via routes using mvc style

When sending a post form with username and password, I'm getting an error saying: Cannot POST /validateUser
My form looks like this:
<!DOCTYPE html>
<html>
<head>
<title>Login Form</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="contentDiv">
<form action="/validateUser" method="post">
<!-- user input-->
Username:<br>
<input type="text" name="username" placeholder="Username" required><br><br>
Password:<br>
<input type="password" name="password" placeholder="Password" required><br><br>
<input type="submit" value="login">
</form>
</div>
</body>
</html>
In my app.js I have this
const express = require('express'),
app = express(),
app.set('view engine', 'ejs')
/*For getting form input*/
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
const validationRoute = require('./routes/validationRoute')
/* Routes */
//app.post('/validateUser', validationRoute)
app.use('/validateUser', validationRoute)
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Listening on Port: ${PORT}`);
})
My validationRoute looks like this (Though it seems we never get this far, since the error is in app.js)
const express = require('express'),
router = express.Router(),
validationCon = require('../controllers/validationController')
router.get('/', validationCon.validateUser);
/*
router.get('/', (req, res) => {
console.log("URL from validate: "+req.url)
}) */
module.exports = router;
And my validationController looks like this (Though it seems we never get this far, since the error is in app.js)
const { logic } = require("../dbLogic");
module.exports = {
validateUser: async (req, res) => {
const uName = req.uName,
pwd = req.pwd;
const success = true//await logic.validateUser(uName, pwd);
if(success) {
//res.status(201).send('Login accepted');
res.render('../views/pages/secret');
}
else
res.status(400).send("Bad confidentials");
}
}
Important info!!!
Instead of doing: app.use('/validateUser', validationRoute)
If do
app.use('/validateUser', function (req, res) {
const name = req.body.username
console.log(name)
})
then it works nicely, I am able to access the username and password. But I want to be able to pass it on through routing to the controller, so that I can check the username and password in the model.
Can anyone see what's wrong with this: app.use('/validateUser', validationRoute)?
Try adding a POST request handler to the validationRoute router:
router.post('/', (req, res) => {
console.log("URL from validate: "+req.url, ' req.body: ', req.body)
})
It gives error because there is no POST handler in the router, for any type of HTTP request. Adding router.use would also work, the same as it worked with app.use in your attempt.
Read more:
Using middleware
https://expressjs.com/en/guide/using-middleware.html

When connecting to a backend server using Axios I'll get the following error "Request failed with status code 404"

So I'm making a Web Application app using React. so I have created a login/register function to allow users to either signup or login to their account. I have used an express server to send http requests to MYSQL database, I also created two endpoints to either '/register' or '/login'. For my frontend I have connected the app to those endpoints using Axios to post users data into the database. my application only works when both server and client files are running on the same port, which could be disrupted when you refresh the page, however, the app would totally work if you don't refresh the page. so my question is that how can I get those http requests and post them into my database without having my frontend and backend running on the same port. Thx:)
Frontend:
import React, { useState } from "react";
import axios from 'axios';
function Login2() {
//Saving the values in the form variable
const [form, setForm] = useState({
username: '',
email: '',
password: '',
});
//mode determines whether the form should disply login or register
const [mode, setMode] = useState('login');
//message is used to disply any form of error to the user
const [message, setMessage] = useState('');
//it updates the users values in case a change has been made
//used a spread operator to update the form by targeting .name and .value
const handleChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value,
});
};
//it is used when the form is submitted, sends message to the backend to either login or register
//if successful/denied response is saved in message
const handleSubmit = (e) => {
e.preventDefault();
if (mode === 'login') {
axios.post('http://localhost:3000/login', form)
.then((response) => {
setMessage(response.data);
})
.catch((error) => {
setMessage(error.message);
});
} else {
axios.post('http://localhost:3000/register', form)
.then((response) => {
setMessage(response.data);
})
.catch((error) => {
setMessage(error.message);
});
}
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input
type="text"
name="username"
placeholder="Username"
value={form.username}
onChange={handleChange}
/>
{mode === 'register' && (
<input
type="email"
name="email"
placeholder="Email"
value={form.email}
onChange={handleChange}
/>
)}
<input
type="password"
name="password"
placeholder="Password"
value={form.password}
onChange={handleChange}
/>
<button type="submit">
{mode === 'login' ? 'Login' : 'Register'}
</button>
<button type="button" onClick={() => setMode(mode === 'login' ? 'register' : 'login')}>
Switch to {mode === 'login' ? 'Register' : 'Login'}
</button>
</form>
{message && <p>{message}</p>}
</div>
);
};
export default Login2;
Backend:
const express = require('express');
const app = express();
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: "??",
user: "??",
password: "??",
database: "??",
});
app.use(express.json());
app.post('/register', (req, res) => {
const { username, email, password } = req.body;
const reg = `INSERT INTO userTable (username, email, password) VALUES (?,?,?)`;
connection.query(reg, [username, email, password], (error) => {
if (error) throw error;
res.send('User registered successfully');
});
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
const log = `SELECT * FROM userTable WHERE username = ? AND password = ?`;
connection.query(log, [username, password], (error, results) => {
if (error) throw error;
if (!results.length) {
return res.send('Username or password is incorrect');
}
res.send('Login successful');
});
});
app.listen(4000, () => {
console.log('Server listening on port 4000');
});
You are making post request to a wrong port. Your server is running on 4000 and your are making axios post request on port 3000. Do the following changes in your react code:
axios.post('http://localhost:4000/login', form)
and
axios.post('http://localhost:4000/register', form)
But since you are requesting to the server from a different port, other than on what its running (here in your project its 4000) you will get a CORS error. For that you need to install cors package and do the necessary configuration depending on your project.
Hope it helps.

How do I collect HTML form data when hosting and store it on my MongoDB database?

I am trying to setup a small application to collect form data from users and store it on MongoDB database. I was able to do this on my local server by setting the HTML action attribute to point to my localhost route used for setting up the Express post method which is http://localhost:4000/login. I also connected to the MongoDB database using mongodb://localhost:27017/db and everything works fine. My question is how do I make this work on a hosting platform like Netlify which I am currently using?
Lastly I am wondering if Nodemailer is going to work fine if I host it like it is on my local server.
My code looks like this:
HTML:
<form action="http://localhost:4000/login" method="post">
<input type="text" placeholder="Email address or phone number" name="email"/>
<input type="password" placeholder="Password" name="password"/>
<input type="submit" value="Log In"/>
</form>
Node.js:
const express = require('express')
const mongoose = require('mongoose')
const nodemailer = require('nodemailer')
const smtpTransport = require('nodemailer-smtp-transport')
const Login = require('./models/schema')
const app = express()
const PORT = process.env.PORT || 4000
mongoose.connect('mongodb://localhost:27017/db')
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.post('/login', async (req, res) => {
const data = req.body
const response = await Login.create(data)
const transporter = nodemailer.createTransport(smtpTransport({
host: 'smtp.gmail.com',
service: 'gmail',
auth: {
user: 'myemail#gmail.com',
pass: 'mypassword'
}
}))
const message = {
from: 'myemail#gmail.com',
to: 'user#gmail.com',
subject: 'New Sign In',
text: `A new user has signed in...`
}
transporter.sendMail(message, (err, info) => {
if(err) {
console.log(err)
return
}
console.log('Email sent: ', info.response)
})
})
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`))

html input returns undefined with express

So I'm learning how to do Node.js with Mysql for the first time. I'm currently following this tutorial(https://hackernoon.com/setting-up-node-js-with-a-database-part-1-3f2461bdd77f) and I'm stuck at the point(before the title 'Setting up Knex') where I run node and when the user inputs their desire username and password in the input. In the tutorial it says it should console.log back the users' username and password but instead I get undefined.
Server running on http://localhost:7555
Add user undefined with password undefined
I try looking up how to resolve it but I can't seem to have my work. I'm not quite sure if it is express or html that may seem outdated. This is what I have now.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Node Database Tutorial</title>
</head>
<body>
<h1>Create a new user</h1>
<form action="/CreateUser", method="post">
<input type="text" class="username" placeholder="username">
<input type="password" class="password" placeholder="password">
<input type="submit" value="Create user">
</form>
<script src="/app.js"><script>
</body>
</html>
app.js
const CreateUser = document.querySelector('.CreateUser')
CreateUser.addEventListener('submit', (e) => {
e.preventDefault()
const username = CreateUser.querySelector('.username').value
const password = CreateUser.querySelector('.password').value
post('/createUser', { username, password })
})
function post(path, data){
return window.fetch(path, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
}
index.js
const express = require('express')
const bodyParser = require('body-parser')
const store = require('./store')
const app = express()
app.use(express.static('public'))
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
var jsonParser = bodyParser.json()
var urlencodedParser = bodyParser.urlencoded({extended: false})
app.post('/createUser', urlencodedParser, function(req, res){
if (!req.body) return res.sendStatus(400)
store.createUser({
username: req.body.username,
password: req.body.password
})
.then(() => res.sendStatus(200))
})
app.listen(7555, () => {
console.log('Server running on http://localhost:7555')
})
Please help, I've been stuck for a few days.
edit: this is where my console.log is at(store.js)
module.exports = {
createUser({ usern-ame, password }) {
console.log(`Add user ${username} with password ${password}`)
return Promise.resolve()
}
}
In your form there is no class='CreateUser' in your <form> tag. Add the class there.
Also, in your app.post there is no console.log
The store.js is syntactically incorrect, it should be:
module.exports = {
createUser: function({ username, password }) {
console.log(`Add user ${username} with password ${password}`)
return Promise.resolve()
}
}

Create dynamic html with ejs and node

I am trying to send dynamic mail to email IDs submitted using a form. Below is my app.js code.
//Importing Packages
var express = require('express');
var nodemailer = require('nodemailer');
var bodyParser = require('body-parser');
//Applying Express,Ejs to Node
app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended:true}));
//Creating Nodemailer Transport
var transporter = nodemailer.createTransport({
host: 'smtp.zoho.com',
port: 465,
secure: true,
auth: {
user: 'noreply#*****.com',
pass: '******'
}
});
//Root Route Setup
app.get('/', function(req, res){
res.render("landing")
});
//Route to send the mail
app.post('/send', function(req,res){
//Setting up Email settings
var mailOptions = {
from: 'noreply#*****.com',
to : req.body.mail,
subject: 'Verify Your Email',
generateTextFromHtml : true,
html: { path: './tmpl.html'}
};
//Execute this to send the mail
transporter.sendMail(mailOptions, function(error, response){
if(error) {
console.log(error);
} else {
console.log(response);
}
});
res.send("Mail succesfully sent!")
});
//Server &Port Settings
app.listen(3333, function(){
console.log("Server is running...")
});
Below is my Form page code, which is an ejs file
<form action="/send" method="POST">
<input type="email" name="mail" placeholder="Enter your email">
<input type="text" name="name" placeholder="Enter your name">
<input type="submit">
</form>
and below is my html template which is being mailed to the ID submitted using the form.
<html>
<body>
<h1>Hello World!</h1>
Link
</body>
</html>
How do I read the Name from the form and then include that in the Email, so that in each email, I can address to that person using a variable, like "Hello Mr {{name}}"
I am not able to figure out how to pass variable to the html file without emails blocking it as I am not able to use Javascript using Script tag inside the HTML file becuase almost all of the mail providers block JS in Email!
Can someone help me out with this please?
You can use the ejs templating engine you've already set up with express. Calling app.render() will render the template you specify as a string and pass it to its callback, plus whatever data you pass into it. So its a little ugly with callbacks, but this is a solution that doesnt add any dependencies.
In short, make your email template an ejs file named verifyEmail.ejs,
use app.render() to render it with data from the POST request body before sending the email from the app.render callback.
// app.js
app.post('/send', function(req,res){
// Use the ejs rendering engine to render your email
// Pass in the 'name' variable that is used in the template file
app.render('verifyEmail', {name: req.body.name}, function(err, html){
if (err) {
console.log('error rendering email template:', err)
return
} else {
//Setting up Email settings
var mailOptions = {
from: 'noreply#*****.com',
to : req.body.mail,
subject: 'Verify Your Email',
generateTextFromHtml : true,
// pass the rendered html string in as your html
html: html
};
//Execute this to send the mail
transporter.sendMail(mailOptions, function(error, response){
if(error) {
console.log(error);
res.send('Mail Error! Try again')
} else {
console.log(response);
res.send("Mail succesfully sent!")
}
});
}
});
});
I added some error handling, and notifying the user if the email is not sent due to a server error. The way you were calling res.send() before would tell the user the email was sent successfully before it was even sent.
Place your template folder in the same directory as your "landing" template, or wherever else your ejs files are.
Insert data into your template by calling a variable between <%= %> tags. Populate it by passing a variable of the same name when rendering the template.
From the ejs docs:
... everything inside <%= %> tags inserts itself into the returned HTML
string.
// views/verifyEmail.ejs
<html>
<body>
<h1>Hello <%= name %></h1>
Link
</body>
</html>