I am creating a request quote form in nextjs using sendgrid as a thirdparty api for sending emails / submitting request quote from form. I keep receiving the following error and I am unable to link the form to the email.
error - ResponseError: Unauthorized
at node_modules/@sendgrid/client/src/classes/client.js:146:29
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 401,
response: {
headers: {
server: 'nginx',
date: 'Wed, 18 Jan 2023 17:25:46 GMT',
'content-type': 'application/json',
'content-length': '116',
connection: 'close',
'access-control-allow-origin': 'https://sendgrid.api-docs.io',
'access-control-allow-methods': 'POST',
'access-control-allow-headers': 'Authorization, Content-Type, On-behalf-of, x-sg-elas-acl',
'access-control-max-age': '600',
'x-no-cors-reason': 'https://sendgrid.com/docs/Classroom/Basics/API/cors.html',
'strict-transport-security': 'max-age=600; includeSubDomains'
},
body: { errors: [Array] }
},
page: '/api/contact'
}
Under pages/contact.jsx
const contact = () => {
const [values, setValues] = useState({
firstName: "",
lastName: "",
phone: "",
email: "",
zip: "",
message: "",
});
const {firstName, lastName, phone, email, zip, message} = values;
const handleChange = e =>
setValues({ ...values, [e.target.name]: e.target.value });
const handleSubmit = async (e) => {
e.preventDefault()
try {
await fetch("http://localhost:3000/api/contact", {
method: "POST",
header: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
});
} catch (err) {
console.log(err);
}
};
return (
<div className='w-full h-screen'>
<div className='min-h-screen py-40 border border-gray-800 bg-white bg-gradient-to-br from-sjrblue to-sjrblue-200'>
<div className="container mx-auto">
<div className="flex flex-col lg:flex-row w-10/12 bg-white rounded-xl mx-auto shadow-lg overflow-hidden">
<div alt='loaded trailer' className='w-full h-[400px] lg:gap-5 lg:h-auto lg:w-1/2 bg-contactImage bg-cover bg-center text-center shadow-lg shadow-slate-400'></div>
{/* Request Quote Form */}
<div className="lg:w-1/2 lg:m-2 p-4 items-center">
<h2 className='text-3xl mb-4 text-center text-sjrblue'>Company Name</h2>
<p className='mb-4 text-center'>CONTACT US TODAY FOR A <span className='text-blue font-bold'>FREE</span> JUNK REMOVAL ESTIMATE</p>
<form onSubmit={handleSubmit}>
<div className='grid grid-cols-2 gap-1 md:gap-3 lg:gap-5'>
<input
type="text"
placeholder='first name'
value={firstName}
onChange={handleChange}
required
name='firstName'
className='border border-gray-400 py-1 px-2 shadow-lg shadow-slate-400'
/>
<input
type="text"
placeholder='sur name'
value={lastName}
onChange={handleChange}
required
name='lastName'
className='border border-gray-400 py-1 px-2 shadow-lg shadow-slate-400'
/>
</div>
<div className='mt-5'>
<input
type="email"
placeholder='email'
value={email}
onChange={handleChange}
required
name='email'
className='text-sm border border-gray-400 py-1 px-2 w-full shadow-lg shadow-slate-400'
/>
</div>
<div className='mt-5'>
<input
type="tel"
id='phone-number'
onkeydown='phoneNumberFormatter()'
inputmode='tel'
placeholder='phone number 123-456-7890'
pattern='[0-9]{3}-[0-9]{3}-[0-9]{4}'
value={phone}
onChange={handleChange}
required
name='phone'
className='text-sm border border-gray-400 py-1 px-2 w-full shadow-lg shadow-slate-400'
/>
</div>
<div className='mt-5'>
<input
type="text"
inputmode='numeric'
placeholder='zip code'
maxLength={5}
value={zip}
onChange={handleChange}
name='zip'
required
className='text-sm border border-gray-400 py-1 px-2 w-full shadow-lg shadow-slate-400'
/>
</div>
<div className='mt-5'>
<textarea
name="message"
placeholder='message'
id="" cols="30"
rows="10"
value={message}
onChange={handleChange}
required
className='text-sm border border-gray-400 py-1 px-2 w-full shadow-lg shadow-slate-400'>
</textarea>
</div>
<div className='mt-5 text-center'>
<input type="checkbox" required className='border border-gray-400 w-3 h-3'/>
<span className='px-3 text-sm'>I am not a robot</span>
<div className='mt-5'>
<button className='bg-sjrblue w-full text-enter text-white py-3 rounded hover:bg-blue-700 duration-300 shadow-lg shadow-slate-400'>Get your FREE estimate</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
under pages/api/contact.js
require("dotenv").config();
const sgMail = require("@sendgrid/mail");
const { SG_API_KEY, FROM_EMAIL, TO_EMAIL } = process.env;
sgMail.setApiKey(SG_API_KEY);
export default async function handler(req, res) {
const {firstName, lastName, phone, email, zip, message} = req.body;
const msg = {
to: TO_EMAIL,
from: FROM_EMAIL,
subject: '',
html: `<p><strong>First Name: </strong>${firstName}</p>
<p><strong>Last Name: </strong>${lastName}</p>
<p><strong>Phone Number: </strong>${phone}</p>
<p><strong>Email: </strong>${email}</p>
<p><strong>Zip: </strong>${zip}</p>
<p><strong>Message: </strong>${message}</p>
`,
};
await sgMail.send(msg);
console.log('email sent');
res.status(200).json({ success: true });
And I have an .env file in my root files
SG_API_KEY= #API Key
TO_EMAIL= #verified email
FROM_EMAIL= #email to send form to
Please help! Thank you in advance!
Twilio developer evangelist here.
Because it's a 401 error, I think it's an issue with how you set up your API key in environment variables.
To set up environment variables, you can use these 3 commands:
echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env
echo "sendgrid.env" >> .gitignore
source ./sendgrid.env
You could also change your API key settings to Full access in the SendGrid console, or it could be the incorrect API key so you could also generate a new one.