0

I'm trying to set up a form that sends info to my email using sendgrid and Gatsby Functions. I've tried following the gatsby sendgrid example, and the youtube video "four real world solutions using gatsby functions..." but with both I end up getting a authorization/CORS error:

*console error Error Screen *response.body.errors enter image description here *verified single sender enter image description here

I've tried a few things like:

  • adding cors middleware around my function (although I wasn't 100% I did this right)
  • setting res.set({"Content-Type": "application/json" Authorization: `Bearer ${process.env.SENDGRID_API_KEY}` });
  • setting res.setHeader('Access-Control-Allow-Origin', '*')
  • creating new api keys
  • testing gatsby develop & build, clearing cache etc

I'm running out of ideas so any advice would be appreciated :)

code for current form and api is below:

src/api/sendgrid.js

const sgMail = require('@sendgrid/mail')
console.log("api key:" + process.env.SENDGRID_API_KEY, process.env.SENDGRID_AUTHORIZED_EMAIL)
sgMail.setApiKey(process.env.SENDGRID_API_KEY)


export default async (req, res) => {
    res.set({"Content-Type": "application/json",
    Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`
    });
    const msg = {
        to: 'myemail@gmail.com', // Change to your recipient
        from: process.env.SENDGRID_AUTHORIZED_EMAIL, // Change to your verified sender
        subject: 'Sending with SendGrid is Fun',
        text: 'and easy to do anywhere, even with Node.js',
        html: '<strong>and easy to do anywhere, even with Node.js</strong>',
      }
      sgMail
      .send(msg)
      .then(() => {
          console.log('Email sent'); console.log(msg);
      })
      .catch((error) => {
          
          console.error(error);console.log('there was an error');
          return res.status(500).json({
              error: error.response,
          })
          
      })

      return res.status(200)
    

}

src/pages/components/contact.js

const Contact = () => {

    const [serverState, setServerState] = useState({
        formSent: false,
    });

    const {
        register,
        handleSubmit,
        formState: { errors },
      } = useForm()
      const onSubmit = data => {
        fetch(`/api/sendgrid`, {
          method: `POST`,
          body: JSON.stringify(data),
          headers: {
            "content-type": `application/json`,
          },
        })
          .then(res => res.json())
          .then(body => {
            console.log(`response from API:`, body);
          })
      }
    
      console.log({ errors })
    return(
        <div style={{ display: "grid", width: "100%", }} id="contactSection" >


      
        <div
            style={{
            // By using the same grid area for both, they are stacked on top of each other
            gridArea: "1/1",
            position: "relative",
            // This centers the other elements inside the hero component
            placeItems: "center",
            display: "grid",
            width: "100%",
            }}
        >

        <ContactDiv>
        {/* class={serverState.formSent ? "sent" : ""} */}
            <span 
            // css={styles(serverState.formSent)}
            >
                <h1>Message Sent</h1>
                <p>I'll be in touch shortly. Regards, Daniel.</p>
            </span>
            {/* <MobileId id="contactM"/> */}
            <h1 id="contactM">Need a Website?</h1>
            <ContactInfo>
            <p>For a free project consultation call, email or use the form below.</p>
            <p>Mobile:<br/> 022 078 0868</p>
            <p>Email:<br/> daniel@thoughtfulhq.com</p>
            </ContactInfo>
            <div>
                <form 
                onSubmit={handleSubmit(onSubmit)}
                // action="/api/sendgrid" method="POST"
                >
                    <label htmlFor="name">
                            <p>Name:</p>
                            <input 
                                type="text" 
                                name="name" 
                                required  
                                {...register("Name", { required: true, maxLength: 100 })}  
                            />
                    </label>
                    <label htmlFor="email">
                        <p>Email:</p>
                        <input 
                            type="email" 
                            name="email" 
                            required
                            {...register("Email", { required: true, pattern: /^\S+@\S+$/i })}
                        />
                    </label>
                    <label htmlFor="message">
                        <p>Project Details:</p>
                        <textarea 
                            name="message" 
                            id="message" 
                            rows="5" 
                            required
                            {...register("Message", { required: true, maxLength: 2000 })} 
                        />
                    </label>
                    <button type="submit">Submit</button>
                </form>
            </div>
        </ContactDiv>
        </div>
        </div>
    )
    
}

export default Contact;
Daniel Balloch
  • 143
  • 1
  • 2
  • 10
  • 1
    The error looks to be an authorization error, but between your function and SendGrid, not a CORS issue with your front-end. Are you using a [verified email sender](https://docs.sendgrid.com/ui/sending-email/sender-verification) as the from address? – philnash Jul 19 '21 at 05:56
  • Hmm okay. Yep I'm using a verified email. Just tried hardcoding in the api to see if I was doing something wrong with the .env file but I'm still getting the error. It was automatically verified with an authenticated domain if it makes any difference? – Daniel Balloch Jul 21 '21 at 04:21
  • Hmm, that should be ok. In your screenshot of the error, the response has a body that has `errors: [Array]`. Can you inspect `response.body.errors` to find out more precisely what the issue is? – philnash Jul 21 '21 at 04:23
  • Object { message: "The provided authorization grant is invalid, expired, or revoked", field: null, help: null } - I'm pretty sure this is all I'm getting in response.body.errors – Daniel Balloch Jul 21 '21 at 04:32
  • 1
    Are you using the API Key which starts with `SG.`? There is an API Key ID shown in the interface, and that is not the key itself. See [this answer for details](https://stackoverflow.com/questions/34789622/sendgrid-api-key-is-not-working-the-provided-authorization-grant-is-invalid-e). – philnash Jul 21 '21 at 04:37
  • Ok Interesting, think I might have some progress - thank you! I was using the API key, but I just had a look at the link and one of the answers suggests putting the API key right into the sgMail.setApiKey(). This works and the message just sent... the weird thing is the API key console logs from the .env file fine, so I'm not sure why this would be the case, but now I know where to look :) – Daniel Balloch Jul 21 '21 at 04:49
  • 1
    Is there maybe some errant white space in your `.env` file making the API key wrong? Like `SENDGRID_API_KEY= SG.xxx`? – philnash Jul 21 '21 at 04:51
  • Ahh yes that was it, had a comma separating keys in my .env file. Bit silly haha, thanks for all the help! – Daniel Balloch Jul 21 '21 at 05:08

1 Answers1

0

Twilio SendGrid developer evangelist here.

As we worked out in the comments, your SendGrid API key was being stored incorrectly in your .env file. Environment variables should be stored on a new line per variable with no spaces between the variable name and the value, like:

SENDGRID_API_KEY=SG.xxx
SENDGRID_AUTHORIZED_EMAIL=sender@example.com

As an extra note, you should not set an Authorization header on the response to your request to the front-end. This will expose your SendGrid API key to anyone who uses the form if they investigate the response headers. I would recommend removing the line:

    res.set({"Content-Type": "application/json",
      Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`
    });

from src/api/sendgrid.js.

philnash
  • 70,667
  • 10
  • 60
  • 88