0

I am encountering a problem with nodemailer, specifically, transport.sendMail() function.

When running locally using npm start, I can send emails just fine when I access the endpoint 'api/email' with a http.post request. When I push my nodejs app (it serves up an angular project bundles into a dist folder), I can access api/email with gets and posts, but the program freezes at transport.sendMail() with Heroku error code=H12, desc="Request timout"

Here is the nodemailer transporter being created in my nodemailer.service.js file:

const express = require('express');
const router = express.Router();
const nodemailer = require('nodemailer');

/* GET users listing. */
router.get('/', function (req, res, next) {
  res.json({data: 'send something'});
});

let route = router.route('/').options((req, res) => {

});
route.post((req, res, next) => {
  try {
    console.log(req.body);
    let name = req.body.name;
    let senderEmail = req.body.senderEmail;
    let subject = req.body.subject;
    let text = req.body.textBody;
    let transporter;
    try {
      //TODO: TRUE, SO ENTERS HERE
      if (process.env.PRODUCTION) {
        console.log('is production!')

        transporter = nodemailer.createTransport({
          service: process.env.PROD_EMAIL_HOST,
          auth: {
            user: process.env.PROD_EMAIL_UN,
            pass: process.env.PROD_EMAIL_PW
          },
          from: req.body.senderEmail,
          tls: {
            ciphers: 'SSLv3'
          },
          port: process.env.PROD_EMAIL_PORT,
          requireTLS: true,
          secure: false
        });
        console.log('created transport');
      } else {
        console.log('is dev!')
        transporter = nodemailer.createTransport({
          host: process.env.TEST_EMAIL_HOST,
          port: process.env.TEST_EMAIL_PORT,
          auth: {
            user: process.env.TEST_EMAIL_UN,
            pass: process.env.TEST_EMAIL_PW
          },
          from: req.body.senderEmail,
        });
      }
    } catch (e) {
      console.log('OOPS: ' + e.message);
    }

Here is where the message body is created

      message = {
        from: name + ' <' + senderEmail + '>', // Sender address
        to: 'team@berwick-house.com',       // List of recipients
        subject: subject, // Subject line
        text: text, // Plain text body
        html: text // HTML text body
      };
      console.log('got message: ' + message);

And here is transporter.sendMail() where the application just times out when run on Heroku.

    console.log('about to send!!!!')
    transporter.sendMail(message, (error, info) => {
      //TODO: HALTS
      console.log('Sending...');
      if (error) {
        res.status(400).json({data: 'ERROR: ' + error.message, status: error.status});
        console.log('error sending: ' + error.message);
      } else {
        res.status(200).json({data: message, status: 'OK'});
        console.log('success!');
      }
    }).then(r => {
      //TODO: r IS UNDEFINED
      console.log(r);
    });
  } catch (error) {
    console.log('ERROR: ' + error.message);
  }

Any advice would be hugely appreciated! For reference, here is my server.js code

const express = require('express');
const path = require('path');
const cors = require('cors');
const emailRouter = require('./nodesrc/services/nodemailer.service.js');
const versionRouter = require('./nodesrc/services/version.service.js');
const app = express();
const dotenv = require('dotenv');
dotenv.config();

// view engine setup
app.set('view engine', 'jade');

app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/api/email', emailRouter);
app.use('/api/version', versionRouter);


app.use(cors({
  "origin": ["https://berwick-house.herokuapp.com", "http://localhost:8080"],
  "methods": "GET, POST, PUT, DELETE, OPTIONS",
  "optionsSuccessStatus": 200,
  "credentials": true
}));

app.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});




// Serve only the static files form the dist directory.
app.use(express.static(__dirname + '/dist/berwick'));

//Set base index file as into.
app.get('/*', function (req, res) {
  res.sendFile(path.join(__dirname + '/dist/berwick/index.html'));
});


let port = process.env.PORT || 8080;
app.listen(port);

I've read through the Heroku docs, including this https://help.heroku.com/AXOSFIXN/why-am-i-getting-h12-request-timeout-errors-in-nodejs.

Heroku also seems to block some traffic with firewalls if it deems it a threat - maybe that's the case with nodemailer?

Here are the error logs from heroku logs --tail

2022-01-17T01:23:12.598026+00:00 app[web.1]: name: 'will',
2022-01-17T01:23:12.598027+00:00 app[web.1]: senderEmail: 'angelljamesw@gmail.com',
2022-01-17T01:23:12.598027+00:00 app[web.1]: subject: ' Some subject',
2022-01-17T01:23:12.598028+00:00 app[web.1]: textBody: 'ddhdhkdkdsf some text'
2022-01-17T01:23:12.598028+00:00 app[web.1]: }
2022-01-17T01:23:12.598096+00:00 app[web.1]: is production!
2022-01-17T01:23:12.600149+00:00 app[web.1]: created transport
2022-01-17T01:23:12.600205+00:00 app[web.1]: about to start message
2022-01-17T01:23:12.600275+00:00 app[web.1]: got message: [object Object]
2022-01-17T01:23:12.600320+00:00 app[web.1]: about to send!!!!
2022-01-17T01:23:42.577424+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=POST path="/api/email" host=berwick-house.herokuapp.com request_id=7f5a0d6b-89a4-43f8-b27b-d11bc830d2c8 fwd="84.67.165.143" dyno=web.1 connect=0ms service=30000ms status=503 bytes=0 protocol=https
  • could you show the error logs as well? – roger Jan 17 '22 at 02:40
  • Apologies, just edited my question to include this. – will.i.may.be Jan 17 '22 at 10:13
  • I don't suppose anyone might be able to offer some guidance on this? – will.i.may.be Jan 18 '22 at 22:26
  • I was having same issue and on searching I got this and it worked --> https://stackoverflow.com/a/58324490/13049450 – rickster Jan 19 '22 at 04:20
  • Thanks for this @rickster - this is not quite what I'm looking for. SendGrid doesn't support unverified email senders, so on a contact form on my page, I want the user to input their email and message, and then send an email to my custom domain. In essence, I want to _receive_ an email using nodemailer, not send one. Does that make sense? – will.i.may.be Jan 26 '22 at 19:28
  • I realise I'm probably going about this the wrong way - the reason Heroku is so restrictive is security. If I could send emails the way I wanted, with unverified emails, anyone could abuse it and send mail as someone they're not. I'll go ahead and use Heroku's SendGrid add-on, or Mailchimp's service. Add the customers email in the body of the request and the subject as 'Enquiry'. Thanks for your help - there's a very good reason this is not achievable! – will.i.may.be Jan 27 '22 at 11:06

0 Answers0