msippel415
msippel415

Reputation: 25

Nodemailer Node express POST issue Github pages Gmail

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

Answers (2)

msippel415
msippel415

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

djs
djs

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:

Ethereal request

You can find a fork of the project that works as expected here: nodemailer-repo

Upvotes: 1

Related Questions