I’m having an issue with a simple lambda function that sends an email via mailgun — the function returns 200 and works correctly but a 502 error is shown in the client side console.
The site name is twelvenyc.netlify.app.
Here’s the function source code:
// Gatsby settings for the environment variables
require("dotenv").config();
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Credentials": "true",
};
const successCode = 200;
const errorCode = 400;
// Connect to our Mailgun API
const mailgun = require("mailgun-js");
const mg = mailgun({
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN,
});
// Our Netlify function
export function handler(event, context, callback) {
console.log(mg);
let data = JSON.parse(event.body);
let { name, companyName, fromEmail, phoneNumber, message, toEmail } = data;
let bodyText = `Name: ${name}
Company: ${companyName}
Email: ${fromEmail}
Phone Number: ${phoneNumber}
${message}`;
let mailOptions = {
from: `${name} <${fromEmail}>`,
to: toEmail,
replyTo: fromEmail,
subject: "twelvenyc.com Contact Form Submission",
text: `${bodyText}`,
};
// Our MailGun code
mg.messages().send(mailOptions, function (error, body) {
if (error) {
console.log(errorCode, headers, error);
callback(null, {
errorCode,
headers,
body: JSON.stringify(error),
});
} else {
console.log(successCode, headers, body);
callback(null, {
successCode,
headers,
body: JSON.stringify(body),
});
}
});
}
Here’s an example log on the Netlify function console (apiKey replaced with [hidden]):
1:53:02 PM: 2021-10-27T20:53:02.388Z undefined ERROR (node:8) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
1:53:02 PM: ae121626 INFO c {
username: 'api',
apiKey: '[hidden]',
publicApiKey: undefined,
domain: 'mg.twelvenyc.com',
auth: 'api:[hidden]',
mute: false,
timeout: undefined,
host: 'api.mailgun.net',
endpoint: '/v3',
protocol: 'https:',
port: 443,
retry: 1,
testMode: undefined,
testModeLogger: undefined,
options: {
host: 'api.mailgun.net',
endpoint: '/v3',
protocol: 'https:',
port: 443,
auth: 'api:[hidden]',
proxy: undefined,
timeout: undefined,
retry: 1,
testMode: undefined,
testModeLogger: undefined
},
mailgunTokens: {}
}
1:53:03 PM: ae121626 INFO 200 {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Credentials': 'true'
} {
id: '<20211027205302.1.BEC72F2D158A93F1@mg.twelvenyc.com>',
message: 'Queued. Thank you.'
}
1:53:03 PM: ae121626 Duration: 687.05 ms Memory Usage: 67 MB Init Duration: 306.59 ms
And here’s the error I’m seeing in the client side console log:
xhr.js:175 POST https://twelvenyc.com/.netlify/functions/send-email 502
createError.js:17 Uncaught (in promise) Error: Request failed with status code 502
at e.exports (createError.js:17)
at e.exports (settle.js:19)
at XMLHttpRequest.m.onreadystatechange (xhr.js:65)
And just in case, here’s the front-end component that calls the function:
import React, { useState } from "react";
import cx from "classnames";
import { useForm } from "react-hook-form";
import { BlockContent } from "src/components/block-content";
import { ShadowBorder } from "src/components/shadow-border";
import * as styles from "./contact-form.module.css";
const endpoints = {
contact: "https://twelvenyc.com/.netlify/functions/send-email",
};
const axios = require("axios");
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
interface ContactFormProps {
toEmail: string;
bilingual: boolean;
finePrint?: string;
successMessage: any[];
}
export const ContactForm = ({
toEmail = "hello@twelvenyc.com",
bilingual = true,
finePrint,
successMessage,
}: ContactFormProps) => {
const [success, setSuccess] = useState(false);
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const onSubmit = (data: any) => {
// set to email
data.toEmail = toEmail;
// post to lambda function
axios
.post(endpoints.contact, JSON.stringify(data))
.then((response: any) => {
console.log(response);
if (response.status !== 200) {
handleError();
} else {
handleSuccess();
}
});
};
const handleSuccess = () => {
// console.log("success!");
setSuccess(true);
};
const handleError = () => {
console.log("error!");
};
return (
<div className={styles.contactForm}>
{success ? (
<BlockContent
blocks={successMessage}
className={cx("small-body", styles.successMessage)}
/>
) : (
<form noValidate autoComplete="off" onSubmit={handleSubmit(onSubmit)}>
<div className={styles.row}>
<div className={styles.inputContainer}>
<label>
<span className={cx("label", styles.inputLabel)}>
Name{bilingual && <> / Nom</>}*
</span>
<input
type="text"
className={cx("small-body", errors.name ? styles.error : "")}
placeholder={errors.fromEmail && "Required"}
{...register("name", { required: true })}
/>
</label>
</div>
<div className={styles.inputContainer}>
<label>
<span className={cx("label", styles.inputLabel)}>
Company Name{bilingual && <> / Nom de la société</>}*
</span>
<input
type="text"
className={cx(
"small-body",
errors.companyName ? styles.error : ""
)}
placeholder={errors.fromEmail && "Required"}
{...register("companyName", { required: true })}
/>
</label>
</div>
</div>
<div className={styles.row}>
<div className={styles.inputContainer}>
<label>
<span className={cx("label", styles.inputLabel)}>Email*</span>
<input
type="email"
className={cx(
"small-body",
errors.fromEmail ? styles.error : ""
)}
placeholder={errors.fromEmail && "Required"}
{...register("fromEmail", {
required: true,
pattern: {
value: EMAIL_REGEX,
message: "Please enter a valid email address.",
},
})}
/>
</label>
</div>
<div className={styles.inputContainer}>
<label>
<span className={cx("label", styles.inputLabel)}>
Phone Number{bilingual && <> / Téléphone</>}
</span>
<input
className={cx("small-body")}
{...register("phoneNumber")}
/>
</label>
</div>
</div>
<div className={styles.row}>
<div className={styles.inputContainer}>
<label>
<span className={cx("label", styles.inputLabel)}>
Any additional info
{bilingual && <> / Informations complémentaires</>}
</span>
<textarea
className={cx("small-body")}
{...register("message")}
/>
</label>
</div>
</div>
<div className={styles.row}>
<button type="submit" className={cx(styles.submitButton)}>
<ShadowBorder className={styles.submitBorders}>
<div className={styles.submitButtonInner}>
<span className="label">Submit</span>
</div>
</ShadowBorder>
</button>
</div>
{finePrint && (
<p className={cx(styles.finePrint, "small-body")}>{finePrint}</p>
)}
</form>
)}
</div>
);
};