I have a contact form connected to a serverless function netlify/functions/submission-created
<!-- netlify/functions/submission-created.js -->
const sgMail = require("@sendgrid/mail");
const process = require("process");
sgMail.setApiKey(process.env.NETLIFY_EMAILS_PROVIDER_API_KEY);
exports.handler = async (event) => {
const payload = JSON.parse(event.body).payload;
const data = payload.data;
let timestamp = payload.created_at;
let deliveryDate = new Date(timestamp);
const msgToHost = {
to: process.env.NETLIFY_EMAILS_SENDER,
from: `... <${process.env.NETLIFY_EMAILS_SENDER}>`,
replyTo: data.email,
subject: `New enquiry received from ${data.firstName} ${data.lastName}`,
html: "More information...",
};
sgMail
.send(msgToHost)
.then((response) => {
console.log(response[0].statusCode);
})
.catch((error) => {
console.error(error);
});
return {
statusCode: 200,
body: JSON.stringify("Email sent successfully"),
};
};
This function is triggered when the following form is submitted
<!-- _includes/forms/contact.njk -->
<form
name="contact"
action="/message-received.html"
data-netlify="true"
class="email-form"
netlify-honeypot="bot-field"
data-netlify-recaptcha="true"
>
<div class="row gy-4">
<div>
<i class="bi bi-envelope" style="font-size:38px;color:#2e004f;"></i>
<span style="margin-left:1rem; font-size:1.5rem;color:#00046d;font-weight:700;">Send us a message now</span>
</div>
<p style="display:none;">
<label>
Don’t fill this out if you’re human: <input name="bot-field" />
</label>
<input type="hidden" name="form-name" value="contact"/>
<input type="hidden" name="template-id" value="enter-template-id-here"/>
</p>
<div class="col-md-6">
<input type="text" id="firstName" name="firstName" class="form-control" placeholder="Your First Name" required>
</div>
<div class="col-md-6">
<input type="text" id="lastName" name="lastName" class="form-control" placeholder="Your Last Name" required>
</div>
<div class="col-md-12 ">
<input type="email" id="email" name="email" class="form-control" placeholder="Your Email" required>
</div>
<div class="col-md-12">
<textarea class="form-control" id="message" name="message" rows="6" placeholder="Message"></textarea>
</div>
<div class="col-md-12">
<div data-netlify-recaptcha="true"></div>
</div>
<div class="col-md-12 text-center">
<button type="submit">Send Message</button>
</div>
</div>
</form>
<script>
const processForm = form => {
const data = new FormData(form)
const firstName = document.getElementById('firstName').value
const email = document.getElementById('email').value
fetch('/', {
method:'POST',
body: data,
})
.then(()=>{
form.innerHTML = `
<div class="info-box" data-aos="fade-up">
<i class="bi bi-envelope-check"></i>
<h3>Thank you ${firstName} for your message</h3>
<p> </p>
<p>We will respond as quickly as possible.</p>
<p>We have also sent a copy of your message to ${email}</p>
</div>
`;
})
.catch((error)=>{
form.innerHTML = `<div class="form--error">Error: ${error}</div>`;
})
}
const emailForm = document.querySelector('.email-form')
if (emailForm) {
emailForm.addEventListener('submit', e => {
e.preventDefault();
processForm(emailForm);
})
}
</script>
This all works without error when tested in localhost dev, but once deployed to netlify the function fails.
The contact form refreshes and displays the success message, the fetch shows status 200 in the network tab, but there is no response object returned and there is no email delivered.
the function log:
Jun 28, 04:25:15 PM: 1572a0b0 ERROR Error: connect ETIMEDOUT 54.90.52.143:443
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
errno: -110,
code: 'ETIMEDOUT',
syscall: 'connect',
address: 'x.x.x.x',
port: 443,
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [Function: httpAdapter],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: Infinity,
maxBodyLength: Infinity,
validateStatus: [Function: validateStatus],
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'sendgrid/7.7.0;nodejs',
Authorization: 'Bearer SG.xxxxx',
'Content-Length': 597
},
url: '/v3/mail/send',
method: 'post',
data: `{"from":{"email":"a@b.c","name":"X"},"subject":"New enquiry received","personalizations":[{"to":[{"email":"a@b.c"}]}],"content":[{"value":"\\n <div>\\n <p>\\n A new enquiry fromx has been received.\\n </p>\\n <blockquote></blockquote>\\n <p>x'semail address is v@tz.m</p>\\n <p> </p>\\n <p> </p>\\n <p>Delivered: 6/28/2023, 4:22:08 AM</p>\\n </div>\\n ","type":"text/html"}],"reply_to":{"email":"a@x.c"}}`,
baseURL: 'https://api.sendgrid.com/'
},
request: <ref *1> Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
_events: [Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError],
socket: [Function: handleRequestSocket]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: Infinity,
protocol: 'https:',
path: '/v3/mail/send',
method: 'POST',
headers: [Object],
agent: undefined,
agents: [Object],
auth: undefined,
hostname: 'api.sendgrid.com',
port: null,
nativeProtocols: [Object],
pathname: '/v3/mail/send'
},
_ended: false,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 597,
_requestBodyBuffers: [ [Object] ],
_onNativeResponse: [Function (anonymous)],
_currentRequest: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
strictContentLength: false,
_contentLength: 597,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: true,
_closed: false,
socket: [TLSSocket],
_header: 'POST /v3/mail/send HTTP/1.1\r\n' +
'Accept: application/json\r\n' +
'Content-Type: application/json\r\n' +
'User-Agent: sendgrid/7.7.0;nodejs\r\n' +
'Authorization: Bearer SG.xxxxx\r\n' +
'Content-Length: 597\r\n' +
'Host: api.sendgrid.com\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: [Agent],
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/v3/mail/send',
_ended: false,
res: null,
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'api.sendgrid.com',
protocol: 'https:',
_redirectable: [Circular *1],
[Symbol(kCapture)]: false,
[Symbol(kBytesWritten)]: 0,
[Symbol(kEndCalled)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype],
[Symbol(kUniqueHeaders)]: null
},
_currentUrl: 'https://api.sendgrid.com/v3/mail/send',
[Symbol(kCapture)]: false
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
}
It appears that for some reason sendgrid is rejecting the request when it comes from my live site.
Any help appreciated.
TIA
MartyNZ