Home
Support Forums

Netlify function doesn't return any response

I’m implementing a contact form with Nodemailer in React and I’m using Netlify Functions. There’s a weird behavior which is that every time I use that contact form to send an email, the email is sent successfully, yet I get no successful response back. This is what I get in the console:

Request from ::1: POST /.netlify/functions/mailer
{
  formData: {
    firstName: 'Testing',
    lastName: 'Last',
    email: 'testing@gmail.com',
    message: 'This is a test'
  }
}
Server is running on port: 3001
{"level":"error","message":"End - Error:"}
{"errorMessage":"Task timed out after 10.00 seconds","errorType":"TimeoutError","level":"error","stackTrace":["new TimeoutError (C:\\Users\\USUARIO\\AppData\\Roaming\\npm\\node_modules\\netlify-cli\\node_modules\\lambda-local\\build\\lib\\utils.js:112:28)","Context.<anonymous> (C:\\Users\\USUARIO\\AppData\\Roaming\\npm\\node_modules\\netlify-cli\\node_modules\\lambda-local\\build\\lib\\context.js:110:19)","listOnTimeout (node:internal/timers:557:17)","processTimers (node:internal/timers:500:7)"]}
Response with status 500 in 12661 ms.

This is the link of the site I’m building: LynStore

Hi @JuanSebastianM

The function is not finishing (returning a response) within the 10 second time limit. Functions must return a response e.g.

return {
  statusCode: 200,
  body: "Email sent"
}

I’m not sure if I understood what you mean but taking into account your example, that’s exactly what I have in my functions/mailer.js:

require('dotenv').config();
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
const express = require('express');
const path = require('path');
const app = express();
const cors = require('cors');

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

const EMAIL = process.env.REACT_APP_EMAIL;
const CLIENT_ID = process.env.REACT_APP_CLIENT_ID;
const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET;
const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI;
const REFRESH_TOKEN = process.env.REACT_APP_REFRESH_TOKEN;

exports.handler = (event, context, callback) => {
  const userInfo = JSON.parse(event.body);
  console.log(userInfo);

  const oAuth2Client = new google.auth.OAuth2(
    CLIENT_ID,
    CLIENT_SECRET,
    REDIRECT_URI
  );
  oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

  const sendMail = async () => {
    try {
      const accessToken = await oAuth2Client.getAccessToken();
      const transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
          type: 'OAuth2',
          user: EMAIL,
          clientId: CLIENT_ID,
          clientSecret: CLIENT_SECRET,
          refreshToken: REFRESH_TOKEN,
          accessToken: accessToken,
        },
      });
      let mailOptions = {
        from: `${userInfo.formData.firstName} ${userInfo.formData.lastName} <${userInfo.formData.email}>`,
        to: EMAIL,
        subject: `Correo enviado por ${userInfo.formData.firstName} ${userInfo.formData.lastName} desde el sitio web`,
        text: `${userInfo.formData.message}`,
        html: `
              <p>¡Tienes un nuevo correo electrónico enviado desde el sitio web de LynStore!</p>
              <h3>Detalles del contacto:</h3>
              <ul>
                <li>Nombre: ${userInfo.formData.firstName} ${userInfo.formData.lastName}</li>
                <li>Correo: ${userInfo.formData.email}</li>
              </ul>
              <h3>Mensaje:</h3>
              <p>${userInfo.formData.message}</p>
              `,
      };
      const result = await transporter.sendMail(mailOptions);
      return result;
    } catch (err) {
      console.log('Error!!!!!!!', err);
    }
  };
  sendMail()
    .then((result) => {
      return {
        statusCode: 200,
        body: 'Email sent',
      };
    })
    .catch((error) => {
      return {
        statusCode: 400,
        body: 'Failed to send email',
      };
    });
};

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`Server is running on port: ${PORT}`);
});

I still get the same error.

You have a listener which is something not supported by Netlify functions

As reference, here is a function I have used (pretty much the example from nodemailer) sending out using Ethereal Email

Ok, so you mean I should remove that

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`Server is running on port: ${PORT}`);
});

If so, I did and also I read your code and that of Nodemailer (again) and then modified mine. Now it looks like this but I’m getting the same error:

require('dotenv').config();
const nodemailer = require('nodemailer');
const { google } = require('googleapis');

const EMAIL = process.env.REACT_APP_EMAIL;
const CLIENT_ID = process.env.REACT_APP_CLIENT_ID;
const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET;
const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI;
const REFRESH_TOKEN = process.env.REACT_APP_REFRESH_TOKEN;

exports.handler = (event, context) => {
  if (event.httpMethod !== 'POST') {
    return {
      statusCode: 405,
      body: 'Method Not Allowed',
    };
  }
  const userInfo = JSON.parse(event.body);
  console.log('user info:', userInfo);

  const oAuth2Client = new google.auth.OAuth2(
    CLIENT_ID,
    CLIENT_SECRET,
    REDIRECT_URI
  );
  oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

  const sendMail = async () => {
    try {
      const accessToken = await oAuth2Client.getAccessToken();
      const transporter = nodemailer.createTransport({
        service: 'gmail',
        port: 587,
        secure: false,
        auth: {
          type: 'OAuth2',
          user: EMAIL,
          clientId: CLIENT_ID,
          clientSecret: CLIENT_SECRET,
          refreshToken: REFRESH_TOKEN,
          accessToken: accessToken,
        },
      });
      let mailOptions = {
        from: `"${userInfo.formData.firstName} ${userInfo.formData.lastName} 👻" <${userInfo.formData.email}>`,
        to: EMAIL,
        subject: `Correo enviado por ${userInfo.formData.firstName} ${userInfo.formData.lastName} desde el sitio web`,
        text: `${userInfo.formData.message}`,
        html: `
              <p>¡Tienes un nuevo correo electrónico enviado desde el sitio web de LynStore!</p>
              <h3>Detalles del contacto:</h3>
              <ul>
                <li>Nombre: ${userInfo.formData.firstName} ${userInfo.formData.lastName}</li>
                <li>Correo: ${userInfo.formData.email}</li>
              </ul>
              <h3>Mensaje:</h3>
              <p>${userInfo.formData.message}</p>
              `,
      };
      const result = await transporter.sendMail(mailOptions);
      return result;
    } catch (err) {
      console.log('Error!!!!!!!', err);
    }
  };
  sendMail()
    .then((result) => {
      return {
        statusCode: 200,
        header: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          sent: true,
          message: result.messageId,
        }),
      };
    })
    .catch((error) => {
      return {
        statusCode: 400,
        header: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          sent: false,
          message: 'Error. Credential are correct?',
        }),
      };
    });
};

This is the whole log I get after doing netlify dev in the VS Code terminal

Netlify Dev ◈
◈ Ignored general context env var: LANG (defined in process)
◈ Injected .env file env var: REACT_APP_EMAIL
◈ Injected .env file env var: REACT_APP_CLIENT_ID
◈ Injected .env file env var: REACT_APP_CLIENT_SECRET
◈ Injected .env file env var: REACT_APP_REDIRECT_URI
◈ Injected .env file env var: REACT_APP_REFRESH_TOKEN
◈ Loaded function mailer (​http://localhost:8888/.netlify/functions/mailer​).
◈ Functions server is listening on 50334
◈ Starting Netlify Dev with Create React App

> lynstore@0.1.0 start
> react-scripts start

i 「wds」: Project is running at http://idkwhy-but-i-think-i-should-hide-this-ip/
i 「wds」: webpack output is served from
i 「wds」: Content not from webpack is served from C:\Users\USUARIO\Desktop\lynstore\public
i 「wds」: 404s will fallback to /
Starting the development server...

Compiled successfully!

You can now view lynstore in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://not-important:3000

Note that the development build is not optimized.
To create a production build, use npm run build.


   ┌─────────────────────────────────────────────────┐
   │                                                 │
   │   ◈ Server now ready on http://localhost:8888   │
   │                                                 │
   └─────────────────────────────────────────────────┘

Request from ::1: POST /.netlify/functions/mailer
user info: {
  formData: {
    firstName: 'Name',
    lastName: 'Test',
    email: 'testtest@hotmail.com',
    message: 'lololol'
  }
}
{"level":"error","message":"End - Error:"}
{"errorMessage":"Task timed out after 10.00 seconds","errorType":"TimeoutError","level":"error","stackTrace":["new TimeoutError (C:\\Users\\USUARIO\\AppData\\Roaming\\npm\\node_modules\\netlify-cli\\node_modules\\lambda-local\\build\\lib\\utils.js:112:28)","Context.<anonymous> (C:\\Users\\USUARIO\\AppData\\Roaming\\npm\\node_modules\\netlify-cli\\node_modules\\lambda-local\\build\\lib\\context.js:110:19)","listOnTimeout (node:internal/timers:557:17)","processTimers (node:internal/timers:500:7)"]}
Response with status 500 in 12867 ms.

Just in case you need it, this is what I got at netlify.toml:

[build]
    functions = "functions"
    command = "npm run build"

Finally, this is what I get from my submitForm function (the one I use when submitting the form):

Failed to load resource: the server responded with a status of 500 (Internal Server Error) 
ContactForm.js:36 
response 
    Response {
        type: 'basic', 
        url: 'http://localhost:8888/.netlify/functions/mailer', 
        redirected: false, 
        status: 500, 
        ok: false, …}

        body: (...)
        bodyUsed: true
        headers: Headers
             [[Prototype]]: Headers
             ok: false
             redirected: false
             status: 500
             statusText: "Internal Server Error"
             type: "basic"
             url: "http://localhost:8888/.netlify/functions/mailer"
             [[Prototype]]: Response

Error! SyntaxError: Unexpected token T in         ContactForm.js:48
JSON at position 0 

Yes, I meant removing the app.listen :+1:

These are the changes I made (as well as auth which should remain the same for you)

Changed to

exports.handler = async (event, context) => {

Then changed this from…

… to

const res = await sendMail()
if (res.messageId) {
  return {
    statusCode: 200,
    // rest of what you need.
}
return {
  statusCode: 400,
  // rest of what you need
}
1 Like

Thank you so much, man. That fixed it all :clap: :clap:

Just in case someone else runs into the same issue and tries that solution, at first it wasn’t working because I tried it without including:

header: {
        'Content-Type': 'application/json',
      },

in both returns of the if (res.messageId).

This is how it looks like now:

const nodemailer = require('nodemailer');
const { google } = require('googleapis');

const EMAIL = process.env.REACT_APP_EMAIL;
const CLIENT_ID = process.env.REACT_APP_CLIENT_ID;
const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET;
const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI;
const REFRESH_TOKEN = process.env.REACT_APP_REFRESH_TOKEN;

exports.handler = async (event, context) => {
  if (event.httpMethod !== 'POST') {
    return {
      statusCode: 405,
      body: 'Method Not Allowed',
    };
  }
  const userInfo = JSON.parse(event.body);
  console.log('user info:', userInfo);

  const oAuth2Client = new google.auth.OAuth2(
    CLIENT_ID,
    CLIENT_SECRET,
    REDIRECT_URI
  );
  oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

  const sendMail = async () => {
    try {
      const accessToken = await oAuth2Client.getAccessToken();
      const transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
          type: 'OAuth2',
          user: EMAIL,
          clientId: CLIENT_ID,
          clientSecret: CLIENT_SECRET,
          refreshToken: REFRESH_TOKEN,
          accessToken: accessToken,
        },
      });
      let mailOptions = {
        from: `"${userInfo.formData.firstName} ${userInfo.formData.lastName} ✨" <${userInfo.formData.email}>`,
        to: EMAIL,
        subject: `Correo enviado por ${userInfo.formData.firstName} ${userInfo.formData.lastName} desde el sitio web`,
        text: `${userInfo.formData.message}`,
        html: `
              <p>¡Tienes un nuevo correo electrónico enviado desde el sitio web de LynStore!</p>
              <h3>Detalles del contacto:</h3>
              <ul>
                <li>Nombre: ${userInfo.formData.firstName} ${userInfo.formData.lastName}</li>
                <li>Correo: ${userInfo.formData.email}</li>
              </ul>
              <h3>Mensaje:</h3>
              <p>${userInfo.formData.message}</p>
              `,
      };
      const result = await transporter.sendMail(mailOptions);
      return result;
    } catch (err) {
      console.log('Error!!!!!!!', err);
    }
  };
  const res = await sendMail();
  if (res.messageId) {
    return {
      statusCode: 200,
      header: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        sent: true,
        message: res.messageId,
      }),
    };
  }
  return {
    statusCode: 400,
    header: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      sent: false,
    }),
  };
};

1 Like