I have created a contact form and trying to use nodemailer to send the message to my email, but not sure where is the issue.
I created a server.js and put it in the main folder while Mailer.js that contain the form in components
I am not sure how the server know that I want to use the form
this is my first project on React and I think I still don't understand some basics of React
const express = require('express');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const path = require('path');
const nodemailer = require('nodemailer');
const app = express();
// View engine setup
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.render('contact');
});
app.post('/send', (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Email: ${req.body.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL, // generated ethereal user
pass: process.env.PASSWORD // generated ethereal password
},
tls:{
rejectUnauthorized:false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: process.env.EMAIL, // sender address
to: email, // list of receivers
subject: 'Node Contact Request', // Subject line
text: 'Hello world?', // plain text body
html: output // html body
};
// send mail with defined transport object
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('contact', {msg:'Email has been sent'});
});
});
app.listen(3000, () => console.log('Server started...'));
This is the form
import React from 'react';
import "./Mailer.scss";
const Mailer = () =>{
return (
<div className="container">
<div className="section ContactPage">
<div className="ContactPage-banner">
<h1 className="ContactPage-banner__title">Contact Us</h1>
</div>
<div className="ContactPage-content">
<form method="POST" className="form" action="send">
<div className="row">
<label className="labels">Name</label>
<input type="text" name="name" className="input"/>
</div>
<div className="row">
<label className="labels">Email</label>
<input type="email" name="email" className="input"/>
</div>
<div className="row">
<label className="labels">Message</label>
<textarea name="message" rows='4' className="input"/>
<input type="submit" value="Send"/>
</div>
</form>
</div>
</div>
</div>
);
};
export default Mailer;
this is what I get when I click on SEND
From what I could gather, you're posting to the wrong URL.
In your server app, you create a post handler for /send
However, in your React App, you post to /xxxxx/send (You obscured the xxxxx part)
I advise that you replace your
<form method="POST" className="form" action="send">
With
<form method="POST" className="form" action="http://127.0.0.1:3000/send">
And try again
Related
I'm trying to create a contact form in react with node mailer but Im having the following issue:
Error shown in console on the browser
It says that 404 NOT FOUND but I dont know where is the mistake i have tried changing the listening part of the server file but no luck:
import React from 'react';
import { useState } from 'react';
import './contactForm.css';
import { Footer } from '../../containers';
const FORM_ENDPOINT = "";
const ContactForm = () => {
const [status, setStatus] = useState("Submit");
const handleSubmit = async (e) => {
e.preventDefault();
setStatus("Sending...");
const { name, email, message } = e.target.elements;
let details = {
name: name.value,
email: email.value,
message: message.value,
};
let response = await fetch("http://localhost:3000/contactForm", {
method: 'POST',
headers: {
"Content-type": "application/json;charset=utf-8",
},
body: JSON.stringify(details),
});
setStatus("Submit");
// let result = await response.json();
// alert(result.status);
};
return (
<div className='RO__ContactForm' id='contactForm'>
<div className='RO__ContactForm-title'>
<h3>Contact</h3>
<h1>I'm here to help you level up</h1>
</div>
<div className='RO__ContactForm-content'>
<div className='RO__ContactForm-content_description'>
<p>I'm just on click away to help you take your company
to the next level. Fill in the form to share more
details about the project or your favorite movie.
Either way, I'd love to talk.</p>
<p></p>
</div>
<form
className='RO__ContactForm-content_form'
action = {FORM_ENDPOINT}
onSubmit = {handleSubmit}
method = 'POST'
target='_blank'
>
<div className='RO__ContactForm-content_form_name'>
<div className='RO__ContactForm-content_form_nameTitle'>
<h5>What's your name?</h5>
</div>
<input
className='RO_ContactForm-content_form_nameInput'
type= 'text'
id='name'
name='name' required
/>
</div>
<div className='RO__ContactForm-content_form_email'>
<div className='RO__ContactForm-content_form_emailTitle'>
<h5>Your email</h5>
</div>
<input
className='RO__ContactForm-content_form_emailInput'
type='email'
id='email['
name='email' required
/>
</div>
<div className='RO__ContactForm-content_form_info'>
<div className='RO__ContactForm-content_form_infoTitle'>
<h5>What can I help you with?</h5>
</div>
<textarea
className='RO__ContactForm-content_form_infoContent'
id='message'
name='message' required
/>
</div>
<div className='RO__ContactForm-content_form_button'>
<button type='submit'>{status}</button>
</div>
</form>
</div>
<div className='RO__ContactForm-footer'>
<Footer />
</div>
</div>
)
}
export default ContactForm
and here is the server file that I use to initialize the server to send the email. That file is made for the contact form front end, and the following file (server.js) its the following;:
const express = require("express");
const router = express.Router();
const cors = require("cors");
const nodemailer = require("nodemailer");
const app = express();
app.use(cors());
app.use(express.json());
app.use('/', router);
app.listen(3000, () => console.log("Server Running"));
const contactEmail = nodemailer.createTransport({
service: "Hotmail",
auth: {
user: '*************#hotmail.com',
pass: '************',
},
});
contactEmail.verify((error) => {
if(error){
console.log(error);
}
else{
console.log("Ready to Send");
}
});
router.post("/contactForm", (req, res) => {
const name = rew.body.name;
const email = req.body.email;
const message = req.body.message;
const mail = {
from: name,
to: 'invariant.rafael.3096#getDefaultNormalizer.com',
subject: 'Contact Form Submission',
hmtl: '<p>Name: ${name} </p> <p>Email: ${email}</p> <p>Message: ${message}</p>',
};
contactEmail.sendMail(mail, (error) => {
if(error){
res.json({ status: 'Error'});
}
else{
res.json({ status: 'Message Sent' });
}
});
});
React typically hosts on port 3000. Change the express server to run on a different port: app.listen(CHANGEME, () => console.log("Server Running"));
If that doesn't work try making some fetch requests somewhere else e.g. https://api.publicapis.org/entries which is a free testing API. Then you will know whether the problem is with your server or not.
Hi I am attempting to use nodemailer with gmail to create a contact form on my website however, I believe there is a routing issue that is causing the mail to be sent but I cannot mange to fix it.
My about.html page contains the code form below:
<form id="contact" action="/contact" id="contact-form" method="post" role="form">
<h3>Contact Form</h3>
<fieldset>
<input placeholder="Your name" type="text" tabindex="1" id="name" name="name" required autofocus>
</fieldset>
<fieldset>
<input placeholder="Subject" type="text" tabindex="1" id="subject" name="subject" required>
</fieldset>
<fieldset>
<input placeholder="Your Email Address" type="email" tabindex="2" id="email" name="email" required>
</fieldset>
<fieldset>
<textarea placeholder="Type your message here...." tabindex="5" id="message" name="message" required></textarea>
</fieldset>
<fieldset>
<button name="submit" type="submit" id="contact-submit" data-submit="...Sending">Submit</button>
</fieldset>
</form>
And my app.js file that is the node server contains the code
//safe enviroment variables
require('dotenv').config();
//express routing
var express = require("express");
var app = express();
var router = express.Router();
var path = __dirname + '/views/';
app.use(express.static('public'));
router.use(function (req,res,next) {
console.log("/" + req.method);
next();
});
router.get("/",function(req,res){
res.sendFile(path + "index.html");
});
router.get("/about",function(req,res){
res.sendFile(path + "about.html");
});
app.use("/",router);
app.use("*",function(req,res){
res.sendFile(path + "404.html");
});
app.listen(8080, function () {
console.log('Example app listening on port 8080!')
})
//nodemail
const nodemailer = require('nodemailer')
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: true}))
//collecting gmail username and password
const GMAIL_USER = process.env.GMAIL_USER
const GMAIL_PASS = process.env.GMAIL_PASS
// POST route from contact form
app.post("/contact", (req, res) => {
async function main() {
// Instantiate the SMTP server
const smtpTrans = nodemailer.createTransport({
service: 'Gmail',
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: GMAIL_USER,
pass: GMAIL_PASS
}
})
// Specify what the email will look like
const mailOpts = {
from: GMAIL_USER , // This is ignored by Gmail
to: GMAIL_USER,
subject: `${req.body.subject}`,
text: `${req.body.name} (${req.body.email}) says: ${req.body.message}`
}
// Attempt to send the email
smtpTrans.sendMail(mailOpts, (error, response) => {
if (error) {
console.log('error email')
res.sendFile(path + "index.html"); // Show a page indicating failure
}
else {
console.log('email sent')
res.sendFile(path + "about.html"); // Show a page indicating success
}
})
}
})
However when clicking the submit button the form it send me to the 404 page indicating that the form cannot find the post function since if it could then it would not redirect me to the post function. I have also added echos into the function to print to console if it is called which does not happen. I have tried changing the routing but can't seem to get it to work.
I am trying to make a post request from a html form and cant figure out where im going wrong.
> <form action="/api" method="POST">
<label for="username">username or email address</label>
<input name="username" id="username" type="text">
<label for="password">password</label>
<input id="password"name="password" type="text">
<button >Log in</button>
</form>
here is my main javascript file for the html (not the server)
"use strict"
let options = {
headers:{
"Content-Type" : "application/json"
},
method: "POST",
}
// fetch("/api",options)
And here is my node js server
"use strict"
//Installing express
let express = require(`express`)
let app = express()
app.use(express.json())
//running the server
app.listen(3000,()=>{
console.log("server is running boi");
})
//Middleware to load the static content
app.use(express.static(`public`))
//Database stuff
let Datastore = require('nedb')
let db = new Datastore({ filename: 'database.db' });
db.loadDatabase()
db.insert({username:"sid", password:"westham"})
//Handler for any post requests made
app.post(`/api`,(req,res)=>{
console.log("request was made");
console.log(req.body);
})
Two Observations
No middleware found in your server.js file for handling form data,
use body-parser http://expressjs.com/en/resources/middleware/body-parser.html
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true });
In your html form, if you're not submitting form with JavaScript then mentiod button type as submit
<button type="submit" >Log in</button>
Im trying to figure out why my post Method won't insert the user made in the register form into my user array, and no array is logged in node. When the register button is clicked, the site is also not redirecting to the /login page. Im not looking for the exact solution maybe just a tip to help me on the right path.
(all libraries is required)
The POST method im using
const express = require('express')
const app = express()
const bcrypt = require('bcrypt');
// helps finding specifik path
const path = require('path')
const port = 3000
// users array
const users = [];
app.use(express.static('views'))
app.listen(port,()=>{
console.log("App is listening on port 3000")
});
// VIGTIGT: tilader at vi kan hente data fra forms via "Name" tagget i formen!
app.use(express.urlencoded({ extended: false }))
// req router fra .auth/user_auth
// Routing: We are mapping to a special respond, and responds a HTML filer
app.get('/contact',(req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/contact.html'))
})
app.get('/login',(req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/login.html'))
})
app.get('/register',(req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/register.html'))
})
app.get('/home',(req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/home.html'))
})
app.get('/portfolio',(req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/portfolio.html'))
})
app.get('/adminpage', (req,res)=>{
res.sendFile(path.resolve(__dirname,'./html/adminpage.html'))
})
// post metoder fra form
app.post('/register', async (req, res)=>{
try{
const hashedPassword = await bcrypt.hash(req.body.password, 10)
users.push({
id: Date.now().toString(),
name: req.body.username,
email: req.body.email,
password: hashedPassword
})
res.redirect('/login')
} catch{
res.redirect('/register')
}
console.log(users)
})
form im using
<form>
<div class="container">
<h1>Register</h1>
<p>Please fill in this form to create an account.</p>
<hr>
<label for="username"><b>Username</b></label>
<input type="text" placeholder="Enter username" name="username" required>
<label for="email"><b>Email</b></label>
<input type="text" placeholder="Enter Email" name="email" required>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" required>
<hr>
<p>By creating an account you agree to our Terms & Privacy.</p>
<button href="/login" type="submit" class="registerbtn">Register</button>
</div>
<div class="container signin">
<p>Already have an account? Sign in.</p>
</div>
</form>
Firstly, you need to specify a method and an action to determine where the data is being sent to:
<form action="/register" method="POST">
</form>
Secondly, you are not parsing the incoming data when it is received by your server. The req.bodysyntax implies that the data is received as an object/JSON, but I don't see anything in your code that indicates you are doing this.
You can use one of a number of packages to do this for you, and Express has built-in middleware for this purpose. I'd recommend the body-parser package.
const bodyParser = require('body-parser');
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }))
Worth adding a temporary console.log(req.body) to your function too just to check form data is being received as intended.
Here is a link to the repo: https://github.com/mcs415/nodemailer-heroku
The repo is basically a replica of Brad Travery's tutorial: https://www.youtube.com/watch?v=nF9g1825mwk
The node server works on localhost, but when I submit I get a POST error and I get no information after that.
I started searching for Nodemailer POST error on the web then I came to the conclusion it was probably express.
I'm using Gmail. It was initially suggested to use Zoho mail at first. Im using Apps less secure option, the code on the repo has no password filled in. I thought I would deal with the POST error first.
I set up Heroku and then tried to create the app via the CLI, it looked good then I got an err for: no start script, I searched that and found to include a line after the test in the JSON file, then my server neglected to run at all. So one thing at a time. First POST error, then Heroku, then GMAIL, possibly 0auth option or another email account.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Contact Morgan</title>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.css" />
<link rel="stylesheet" href="public/css/style.css">
</head>
<body>
<div class="container">
<h1 class="brand"><span>Acme</span> Web Design</h1>
<div class="wrapper animated bounceInLeft">
<div class="company-info">
<ul>
<li><i class="fa fa-road"></i></li>
<li><i class="fa fa-phone"></i></li>
<li><i class="fa fa-envelope"></i> msippel415#gmail.com</li>
</ul>
</div>
<div class="contact">
<h3>Email Us</h3>
{{msg}}
<form method="POST" action"/send">
<p>
<label>Name</label>
<input type="text" name="name">
</p>
<p>
<label>Company</label>
<input type="text" name="company">
</p>
<p>
<label>Email Address</label>
<input type="email" name="email">
</p>
<p>
<label>Phone Number</label>
<input type="text" name="phone">
</p>
<p class="full">
<label>Message</label>
<textarea name="message" rows="5"></textarea>
</p>
<p class="full">
<button type="submit">Submit</button>
</p>
</form>
<p>Thank you Brad at Traversy media for the tutorial!</p>
</div>
</div>
</div>
</body>
</html>
app.js:
const express = require('express');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const path = require('path');
const nodemailer = require('nodemailer');
const app = express();
// View engine setup
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.render('contact', {layout: false});
});
app.post('/send', (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'msippel415#gmail.com', // generated ethereal user
pass: '********' // generated ethereal password
},
tls:{
rejectUnauthorized:false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: '"Nodemailer Contact" <msippel415#gmail.com>', // sender address
to: 'msippel415#gmail.com', // list of receivers
subject: 'Node Contact Request', // Subject line
text: 'Hello world?', // plain text body
html: output // html body
};
// send mail with defined transport object
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('contact', {msg:'Email has been sent'});
});
});
app.listen(3000, () => console.log('Server started...'));
json
{
"name": "nodecontactform",
"version": "1.0.0",
"description": "sample app using nodemailer",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "mcs",
"license": "MIT",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"express-handlebars": "^3.1.0",
"i": "^0.3.6",
"nodemailer": "^6.4.2",
"npm": "^6.13.4"
}
}
Your first error Cannot POST / can be fixed by adding an = sign to your <form> tags action attribute:
<form method="POST" action="/send">
In your version, you were actually making this request POST / when you wanted POST /send.
The other errors are best handled by just copying the code that Nodemailer provides. I pulled in your project and edited app.js to conform to Nodemailer's example and it worked fine. You need to adjust the call to res.render in the POST /send route to add the layout:false option:
res.render('contact', { layout: false, msg:'Email has been sent'});
And you need to generate an ethereal user and use those credentials:
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass // generated ethereal password
}
});
Here is the full code from app.js that I used to get it working:
app.js
const express = require('express');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const path = require('path');
const nodemailer = require('nodemailer');
const app = express();
// View engine setup
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.render('contact', {layout: false});
});
app.post('/send', (req, res) => {
const mailBody = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
sendMail(mailBody).catch(console.error);
res.render('contact', { layout: false, msg:'Email has been sent'});
});
// async..await is not allowed in global scope, must use a wrapper
async function sendMail(html) {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass // generated ethereal password
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo#example.com>', // sender address
to: "bar#example.com, baz#example.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html // html body
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
app.listen(3000, () => console.log('Server started...'));
And here is a gif to show how it looks:
You can find a fork of the project that works as expected here: nodemailer-repo
https://nodemailer-mcs.herokuapp.com/
It took some work to get it on Heroku but I'm happy, with the end result, I wouldnt of done it without dan's help, the ethereal email, gave me a lot of hope. There were some settings with heroku, with a Profile, start script settings and listen on port: process.env.PORT || 3000;