Problem to trigger functions/sendmail with sendgrid in react(endpoint /.netlify/functions/sendmail not found 404)

Hi, first of all I dont´now if I established categories of this discussion well, but I´m going to try it here.
Im trying to send emails from my react web application via netlify functions and I can not trigger the handler of my sendmail.js which is in my functions folder. I´m always getting the same error http:localhost:8080/(here I tried a lot of routes like “.netlify/functions/sendemail”) error 404 not found.

here are my folders, as you can see functions folder is now inside of src folder, but I tried to place it in the root directory and anything the console gives me the same error.

here is a screenshot of the error

I´m trying to send values after a captcha is validated, I made a form with formik and I add all the atribbutes as the documentAtion says

here is my index.html

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="icon" href="favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
     integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
     crossorigin=""/>
     <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
     integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
     crossorigin=""></script>
    <title>Clínica Pal Dental</title>
  </head>
  <body>
    <form method="POST" name="contact-form" data-netlify="true" netlify-honeypot="bot-field" hidden>
      <input type="text" name="NameSurname" />
      <input type="text" name="Phone" />
      <input type="text" name="Email" />
      <textarea name="Comment"></textarea>
      <input type="checkbox" name="LegalConsent" />
      <input name="bot-field" type="hidden" />
    </form>
    <div id="root"></div>
  </body>
</html>

heres is the formik with the useEffect after the captcha is validated

useEffect(() =>{
        async function sendEmailNetlify(){
            
            await fetch(`/.netlify/functions/sendmail`,
            {
                method : "POST", 
                data : formValues
            })
            .then(({ response }) =>{
                debugger;
                alert(JSON.stringify(response))
            })
            .catch(error =>{
                console.log(JSON.parse(error))
            })
            
        }
        if(isCaptchaSent){
            sendEmailNetlify();
        }
    }, [formValues, isCaptchaSent]);

    return(
        <div className="modal fade" id="ContactModal" tabIndex="-1" aria-labelledby="ContactModalLabel" aria-hidden="true">
            <div className="modal-dialog modal-dialog-centered">
                <div className="modal-content">
                    <div className="modal-header justify-content-end">
                        <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <Formik 
                        initialValues={initialContactFormValues} 
                        validationSchema={validationSchema}
                        onSubmit={handleSubmitValues}>
                        {({ resetForm }) => {
                            return(
                                <Form 
                                    id="contactForm" 
                                    name="contact-form"
                                    data-netlify="true"
                                    data-netlify-honeypot="bot-field"
                                    data-netlify-recaptcha="true"
                                    noValidate
                                >
                                    <Field type="hidden" name="bot-field" />
                                    <Field type="hidden" name="form-name" />
                                    <div className="modal-body d-flex flex-column justify-content-start align-items-center mt-n4">
                                        <h5 className="modal-title" id="ContactModalLabel">Contacto</h5>
                                        <h3>Introduce tus datos</h3>
                                        
                                        <div className="form-group">
                                            <label className="form-group__label" htmlFor="NameSurname">
                                                Nombre y apellidos <span className="mandatory">*</span>
                                            </label>
                                            <Field id="NameSurnameInput" name="NameSurname" className="form-group__input"/>
                                            <ErrorMessage name="NameSurname" className="form-group__error" component="span"/>
                                        </div>

                                        <div className="form-group">
                                            <label className="form-group__label" htmlFor="Phone">
                                                Teléfono <span className="mandatory">*</span>
                                            </label>
                                            <div className="input-group flex-nowrap">
                                                <Field id="phoneInput" name="Phone" className="form-group__input"/>
                                                <i className="input-group-text icon icon-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title="El teléfono no puede contener espacios, tampoco es necesario el prefijo" data-bs-custom-class="custom-tooltip"></i>
                                            </div>
                                            <ErrorMessage name="Phone" className="form-group__error" component="span"/>
                                        </div>

                                        <div className="form-group">
                                            <label className="form-group__label" htmlFor="Email">
                                                Email <span className="mandatory">*</span>
                                            </label>
                                            <Field id="emailInput" name="Email" className="form-group__input"/>
                                            <ErrorMessage name="Email" className="form-group__error" component="span"/>
                                        </div>

                                        <div className="form-group">
                                            <label className="form-group__label" htmlFor="Comment">
                                                Comentario <span className="mandatory">*</span>
                                            </label>
                                            <div className="comment">
                                                <Field as="textarea" id="commentInput" name="Comment" className="form-group__input" rows="5"/>
                                            </div>
                                            <ErrorMessage name="Comment" className="form-group__error" component="span" />
                                        </div>

                                        <div className="form-group__legal px-3">
                                            <div className="legal__container">
                                                <Field type="checkbox" id="legalConsentInput" name="LegalConsent" />
                                                <p>He leido y acepto las condiciones de <Link to="/terminos-legales" target="_blank">Aviso Legal</Link> y <Link to="/terminos-legales" target="_blank">Política de privacidad</Link></p>
                                            </div>
                                            <ErrorMessage name="LegalConsent" className="form-group__error ps-0" component="span"/>
                                        </div>
                                        <Reaptcha
                                            ref={rcRef}
                                            sitekey={process.env.RECAPTCHA_SITE_KEY}
                                            data-netlify-recaptcha="true"
                                            onError={onError}
                                            onExpire={onExpire}
                                            onVerify={onVerify}
                                            onLoad={() => onLoad(() => resetForm)}
                                            size="invisible"
                                        />
                                    </div>
                                    <div className="modal-footer justify-content-center">
                                        {renderSubmitButtonState(isSubmitting, executing, verified)}
                                    </div>
                                </Form>
                            )
                        }}
                    </Formik>
                </div>
            </div>
        </div>
    )

heres is my netlify.toml

[[redirects]]
    from = "/*"
    to = "/index.html"
    status = 200

[dev]
  command = "npm start"
  port = 8080
  targetPort = 3000
  publish = "./src/bundles"
  functions = "./src/functions"

[build]
  publish = "./src/bundles"
  functions = "./src/functions"

[functions]
  # Directory with serverless functions, including background
  # functions, to deploy. This is relative to the base directory
  # if one has been set, or the root directory if
  # a base hasn’t been set.
  directory = "./src/functions"
  node_bundler = "esbuild"

here is my sendmail.js

const client = require('@sendgrid/mail');
const {
  SENDGRID_API_KEY,
  SENDGRID_TO_EMAIL,
  SENDGRID_FROM_EMAIL,
} = process.env;

exports.handler = async function (event, context, callback) {
  debugger;
  const { message, senderEmail, senderName } = JSON.parse(event.body);
  client.setApiKey(SENDGRID_API_KEY);

  const data = {
    to: SENDGRID_TO_EMAIL,
    from: SENDGRID_FROM_EMAIL,
    subject: `New message from ${senderName} (${senderEmail})`,
    html: message,
  };

  try {
    await client.send(data);
    return {
      statusCode: 200,
      body: 'Message sent',
    };
  } catch (err) {
    return {
      statusCode: err.code,
      body: JSON.stringify({ msg: err.message }),
    };
  }
};

Netlify Functions can only be run through Netlify CLI, which runs on localhost:8888 by default. Your errors show you’re using localhost:8080 - which would be incorrect unless you’ve configured Netlify CLI explicitly to use that port.

I supposed that, so I changed the port to 8888 and it still giving me the same error, I can’t make trigger the endpoint .netlify/functions/sendmail

It says always 404 not found

Enviado desde Outlook para Android

You don’t have to change the port in your code to 8888. You should simply use relative URLs like /functions/foobar. Once you run Netlify CLI, it will automatically open a browser tab that runs on 8888 and the URL will be resolved automatically.

I run netlify dev, it opens a localhost:8888 y go to endpoint /.netlify/functions/sendmail and it still giving me the same error 404 not found, I did netlify build and netlify deploy as well but nothing changed

Enviado desde Outlook para Android

That would need a reproduction then. Sounds like incorrect configuration to me, which I cannot check without seeing a minimal reproduction.

Finally I use EmailJS to sendEmails because was completely iimpossible to fix this error.

But for future users that want to see if this got fixed, Imagine the same code that I post in my first post, but instead of localhost:8080 is localhost:8888 and if you can please give a solution for that :slight_smile: