Sendgrid email not sending even though sucessful

I am trying to test sending emails for my react website here. I was looking through the documentation

> here and made it through to the part where I send a test email from the Preview UI. I have already put the environment variables and the API key within my netlify site, and when I preview the message it seems fine. I then send the message after doing netlify build and dev from VSCode to launch the localhost/.netlify/functions/emails it says it sends successfully, but the email is not sent and my sendgrid account says there was no attempted API call.

Are you logging the return response from Sendgrid? Does it return a success status? Does it contain a message to confirm it worked or why it failed?

On my sendgrid dashboard it seems as though it never received a request in the first place. I have not yet set up the function for it since according to the documentation it seemed as though it should work before trying to integrate it through the code. I assumed it would be able to send the email directly since the API Key is an environment variable and it says that it sends it successfully.

How are you trying to send an email if not via a function?

It says that I can call it via a function near the bottom

but the documentation says that I should be able to send an email through this preview

Stated in the Trigger an email from your code documentation

To trigger an email directly from your project code, copy and paste your preferred snippet into your project and populate the parameters for your email.

I have tried to update the code and functions to match the documentation

Here is in my App.jsx where I am handling submitting the form

  const handleSubmit = async (e) => {
    e.preventDefault();
    
    const letters = /[a-zA-Z]/;
    if(letters.test(formData.homePhone) || letters.test(formData.cellPhone)){
      alert("Phone numbers cannot have letters")
    }
    else{
      fetch("./.netlify/functions/sendgrid", {
        method: "POST",
        body: JSON.stringify({
          name: formData.name,
          city: formData.city,
          state: formData.state,
          homePhone: formData.homePhone,
          cellPhone: formData.cellPhone,
          email: formData.email
        }),
      });

Here’s my sendgrid.js inside the netlify functions folder

import fetch from 'node-fetch';

const handler = async function (event) {
  if (event.body === null) {
    return {
      statusCode: 400,
      body: JSON.stringify("Payload required"),
    };
  }

  const formData = JSON.parse(event.body);

  await fetch(`\${process.env.URL}/.netlify/functions/emails/sendGridEmail`, {
    headers: {
      "netlify-emails-secret": process.env.NETLIFY_EMAILS_SECRET,
    },
    method: "POST",
    body: JSON.stringify({
      from: "from",
      to: "to",
      subject: "test Subject",
      parameters: {
        name: formData.name,
        city: formData.city,
        state: formData.state,
        email: formData.email,
      },
    }),
  });

  return {
    statusCode: 200,
    body: JSON.stringify("Email sent!"),
  };
};

export default { handler };

I get a 404 error if I leave the fetch as (./.netlify/functions/sendgrid)
and I get a 505 error internal server error if I do (./netlify/functions/sendgrid/sendgrid.js) since that is the file that is actually being refenced

Is there anything else that I’m missing?

This fetch URL is incorrect

Rather

The sendgrid.js function has nothing to stop the return of a 200 status as it isn’t wrapped in a try...catch nor are you capturing the response from the fetch call from the fetch and checking the status or success/error message.

1 Like

Thank you. Now I have updated it to see the error.

First here’s the fixed code just to make sure it seems right.

import fetch from 'node-fetch';

const handler = async function (event) {
  if (event.body === null) {
    return {
      statusCode: 400,
      body: JSON.stringify("Payload required"),
    };
  }

  const formData = JSON.parse(event.body);

  try{
    await fetch(`\${process.env.URL}/.netlify/functions/emails/sendGridEmail`, {
      headers: {
        "netlify-emails-secret": process.env.NETLIFY_EMAILS_SECRET,
      },
      method: "POST",
      body: JSON.stringify({
        from: "from",
        to: "to",
        subject: "test Subject",
        parameters: {
          name: formData.name,
          city: formData.city,
          state: formData.state,
          homePhone: formData.homePhone,
          cellPhone: formData.cellPhone,
          email: formData.email,
        },
      }),
    });

    if(!response.ok){
      return{
        statusCode: response.status,
        body: JSON.stringify(`Email failed to send: ${await response.text()}`),
      };
    }

    return {
      statusCode: 200,
      body: JSON.stringify("Email sent!"),
    };
  }
  catch(error){
    return{
    statusCode: 500,
    body: JSON.stringify(`Server error: ${error}`)
    }
  }
};

export default { handler };

Then here’s the error. It seems as though it is trying to call a lambda function but it does not exist. I assume this means that either something is not being called from the correct path or a file is made incorrectly.

Request from ::1: POST /.netlify/functions/sendgrid
{“level”:“error”,“message”:“End - Error:”}
{“errorMessage”:“lambdaFunc[lambdaHandler] is not a function”,“errorType”:“TypeError”,“level”:“error”,“stackTrace”:[“Object._executeSync (C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:295:47)”,“C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:95:26”,“new Promise ()”,“Object.execute (C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:87:16)”,“Module.invokeFunction (file:///C:/Users/adamp/AppData/Roaming/npm/node_modules/netlify-cli/src/lib/functions/runtimes/js/index.mjs:60:36)”,“NetlifyFunction.invoke (file:///C:/Users/adamp/AppData/Roaming/npm/node_modules/netlify-cli/src/lib/functions/netlify-function.mjs:124:41)”,“processTicksAndRejections (node:internal/process/task_queues:96:5)”,"handler (file:///C:/Users/adamp/AppData/Roaming/npm/node_modules/netlify-cli/src/lib/functions/server.mjs:1Response with status 500 in 224 ms.
Request from ::1: POST /.netlify/functions/sendgrid
{“level”:“error”,“message”:“End - Error:”}
{“errorMessage”:“lambdaFunc[lambdaHandler] is not a function”,“errorType”:“TypeError”,“level”:“error”,“stackTrace”:[“Object._executeSync (C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:295:47)”,“C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:95:26”,“new Promise ()”,“Object.execute (C:\Users\adamp\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\lambda-local\build\lambdalocal.js:87:16)”,“Module.invokeFunction (file:///C:/Users/adamp/AppData/Roaming/npm/node_modules/netlify-cli/src/lib/functions/runtimes/js/index.mjs:60:36)”,“NetlifyFunction.invoke (file:///C:/Users/adamp/AppData/Roaming/npm/node_modules/netlify-cli/src/lib/functions/net59:33)”]}
Response with status 500 in 21 ms.

Here’s the directory in case this helps

Netlify Function don’t export a default as in your code

They export a handler

export { handler };

This is shown in the Create a function to send the email example.

When using JavaScript the general format is

exports.handler = async function (event, context) {
  // your server-side functionality
};

When using Typescript the general format is

import { Handler, HandlerEvent, HandlerContext } from "@netlify/functions";

const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => {
  // your server-side functionality
};

export { handler };

This is taken directly from the Netlify Functions documenation

I tried doing exports.handler but that said I the exports file was considered an ECMAScript module, so I looked into it and it said to either do

module.exports.handler = async function (event, context) {

or

export async function handler(event, context) {

and the second one seemed to work give no errrors. However now when I try to send an email, I get a 500 error again, but this time without any useful information.

Here is the console.log error

Here is the terminal error
image

I didn’t remove the parts of the code where it should return the body with the JSON.stringify of the error so I’m unsure why it is not giving me the details

I had also removed the export default {handler} at the end since according to the documentation it is only needed for typescript

import fetch from 'node-fetch';

export async function handler(event, context) {
  if (event.body === null) {
    return {
      statusCode: 400,
      body: JSON.stringify("Payload required"),
    };
  }

  const formData = JSON.parse(event.body);

  try{
    await fetch(`\${process.env.URL}/.netlify/functions/emails/sendGridEmail`, {
      headers: {
        "netlify-emails-secret": process.env.NETLIFY_EMAILS_SECRET,
      },
      method: "POST",
      body: JSON.stringify({
        from: "from",
        to: "to",
        subject: "test Subject",
        parameters: {
          name: formData.name,
          city: formData.city,
          state: formData.state,
          homePhone: formData.homePhone,
          cellPhone: formData.cellPhone,
          email: formData.email,
        },
      }),
    });
    console.log(response)
    if(!response.ok){
      return{
        statusCode: response.status,
        body: JSON.stringify(`Email failed to send: ${await response.text()}`),
      };
    }

    return {
      statusCode: 200,
      body: JSON.stringify("Email sent!"),
    };
  }
  catch(error){
    return{
    statusCode: 500,
    body: JSON.stringify(`Server error: ${error}`)
    }
  }
};

Remove the \ from in front of the $.

That’s the only thing that jumps out as an issue. I cannot test your code.

I made quite a few changes to make it run. When I go to the link that the const response represents and console.logs, it’s bringing me to the correct place. formData is sending correctly as I can see from the console.log, I tried changing the response await fetch path, but that threw 400 or 404 errors so I must have the correct path since it gives a 200 response.

import fetch from 'node-fetch';

export async function handler(event, context) {
  if (event.body === null) {
    return {
      statusCode: 400,
      body: JSON.stringify("Payload required"),
    };
  }

  const formData = JSON.parse(event.body);
  console.log("This is formData: " + formData.name)

  try{
      const response = await fetch(`${process.env.URL}/.netlify/functions/emails/sendGridEmail`, {
      headers: {
        "netlify-emails-secret": process.env.NETLIFY_EMAILS_SECRET,
      },
      method: "POST",
      body: JSON.stringify({
        from: "placeholder@gmail.com",
        to: "placeholder@gmail.com", //used actual email addresses for testing
        subject: "test Subject",
        parameters: {
          name: formData.name,
          city: formData.city,
          state: formData.state,
          homePhone: formData.homePhone,
          cellPhone: formData.cellPhone,
          email: formData.email,
        },
      }),
    });
    console.log("This is the response: " + response.status)
    if(!response.ok){
      return{
        statusCode: response.status,
        body: JSON.stringify(`Email failed to send: ${await response.text()}`),
      };
    }

    console.log("Email should be sent")
    return {
      statusCode: 200,
      body: JSON.stringify("Email sent!"),
    };
  }
  catch(error){
    console.log("Error: " + error)
    return{
    statusCode: 500,
    body: JSON.stringify(`Server error: ${error}`)
    }
  }
};

image

It says that it should be running successfully, However, the email is never sent, Sendgrid never recognizes that an API call was made, and in the functions section of the netlify page for the website. It says the function has never been called.

image

image

Nevermind, it was going through, it just ended up as spam. Thank you for the help