Emails aren't sending in production, using nodemailer, gmail (gcloud host if that matters). Localhost is fine however

Viewed 147

I have tried a lot of solutions that worked for others on here, but I've been tackling this for a few days and am still at a loss. For some reason, sending emails via localhost works perfectly, but when the site is live, it does not. Here is my code:

app.post('/contact', (req, res) => {

const CLIENT_ID = process.env.C_ID;
const CLIENT_SECRET = process.env.C_SECRET;
const REDIRECT_URI = 'https://developers.google.com/oauthplayground';
const REFRESH_TOKEN = process.env.R_TOKEN;

const oAuth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);

oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

async function sendMail() {

    try {
        const accessToken = await oAuth2Client.getAccessToken();

        const transport = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                type: 'OAuth2',
                user: process.env.EMAIL_USER,
                clientId: CLIENT_ID,
                clientSecret: CLIENT_SECRET,
                refreshToken: REFRESH_TOKEN,
                accessToken: accessToken,
            },
        });

        const mailOptions = {
            from: req.body.email,
            to: process.env.EMAIL_USER,
            subject: `Message from ${req.body.email}`,
            text: req.body.message
        };

        const result = await transport.sendMail(mailOptions)
        return result

    } catch (error) {
        return error
    }
}

sendMail()
    .then((result) => console.log('Email sent: ', result), res.send('success'))
    .catch((error) => console.log(error.message));

});

Here are the main solutions I've tried:

Any ideas? Thank you for reading.

EDIT: To add to this, I'm not getting any error messages no matter what I do. To preface this, I'm relatively new at this.

EDIT*: I tried to send an email via the web server on google cloud SDK(?) and this came up:

Error: No refresh token is set. Which doesn't make too much sense to me.

Also saw this in there which I didn't understand:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

2 Answers

in the nodemailer website you have this: "Even though Gmail is the fastest way to get started with sending emails, it is by no means a preferable solution unless you are using OAuth2 authentication. Gmail expects the user to be an actual user not a robot so it runs a lot of heuristics for every login attempt and blocks anything that looks suspicious to defend the user from account hijacking attempts. For example you might run into trouble if your server is in another geographical location – everything works in your dev machine but messages are blocked in production."

More on using gmail with nodemailer here: https://nodemailer.com/usage/using-gmail/

I found a solution that works for me : you have to add promises with async/await. In my case, I moved to Sendgrid, I had the same bug and I resolve it with this snippet:

import nodemailer from "nodemailer";

export default async (req, res) => {
    require('dotenv').config()
    const nodemailer = require('nodemailer')

    const transporter = nodemailer.createTransport({
      host: 'smtp.sendgrid.net',
      port: 587,
      auth: {
        user: process.env.SENDGRID_USERNAME,
        pass: process.env.SENDGRID_PASSWORD,
      },
    })

    await new Promise((resolve, reject) => {
        // verify connection configuration
        transporter.verify(function (error, success) {
            if (error) {
                console.log(error);
                reject(error);
            } else {
                console.log("Server is ready to take our messages");
                resolve(success);
            }
        });
    });

    const mailData = {
      from: process.env.SENDGRID_SENDER,
      to:  "xxxxx@gmail.com",
      subject: `Message du site par ${req.body.name}`,
      text: req.body.message + " | Envoyé par: " + req.body.email + " | Numéro de tel: " + req.body.tel,
      html: `<div>${req.body.message}</div>
      <p>Envoyé par:${req.body.email}</p>
      <p>Numéro de tel:${req.body.tel}</p>`
    }
    
    await new Promise((resolve, reject) => {
        // send mail
        transporter.sendMail(mailData, (err, info) => {
            if (err) {
                console.error(err);
                reject(err);
            } else {
                console.log(info);
                resolve(info);
            }
        });
    });

    return res.status(200).json({ status: "OK" });
  }

The original answer is here:

Related