Reputation: 25
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> [email protected]</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: '[email protected]', // generated ethereal user
pass: '********' // generated ethereal password
},
tls:{
rejectUnauthorized:false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: '"Nodemailer Contact" <[email protected]>', // sender address
to: '[email protected]', // 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"
}
}
Upvotes: 0
Views: 618
Reputation: 25
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;
Upvotes: 0
Reputation: 4065
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 👻" <[email protected]>', // sender address
to: "[email protected], [email protected]", // 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: <[email protected]>
// 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
Upvotes: 1