提问人: 提问时间:11/7/2023 更新时间:11/7/2023 访问量:17
联系表单无法使用 NextJS 和 Nodemailer
Contact form not working using NextJS and Nodemailer
问:
这是我的 ContactForm.tsx:
"use client";
import { useFormik } from "formik";
import * as Yup from "yup";
import React, { useState } from "react";
import SuccessModal from "@/components/SuccessModal";
interface FormValues {
name: string;
organisation: string;
email: string;
location: string;
number: string;
message: string;
design: boolean;
maintenance: boolean;
repairs: boolean;
}
const ContactForm: React.FC = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [isResetting, setIsResetting] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
setIsResetting(true);
setTimeout(() => {
setIsResetting(false);
formik.resetForm();
}, 500);
};
const formik = useFormik<FormValues>({
initialValues: {
name: "",
organisation: "",
email: "",
location: "south-australia",
number: "",
message: "",
design: false,
maintenance: false,
repairs: false,
},
validationSchema: Yup.object().shape({
name: Yup.string().required("Full Name is required"),
organisation: Yup.string().required("School / Organisation is required"),
email: Yup.string()
.email("Invalid email address")
.required("Email is required"),
location: Yup.string().required("Location is required"),
number: Yup.string().required("Phone number is required"),
message: Yup.string().required("Message is required"),
design: Yup.boolean(),
maintenance: Yup.boolean(),
repairs: Yup.boolean(),
}),
onSubmit: async (values) => {
try {
// Make a POST request to the server-side API route
const response = await fetch("/api/sendEmail", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
if (response.ok) {
console.log("Form values submitted:", values);
openModal();
} else {
console.error("Error sending email");
// Handle the error condition as needed
}
} catch (error) {
console.error("Error sending email:", error);
}
},
});
return (
<div
id="contact"
className="container my-20 px-5 grid gap-8 grid-cols-1 md:grid-cols-2 py-24 mx-auto bg-gray-100 text-gray-900 rounded-lg"
>
<div className="flex flex-col justify-center">
<div>
<h2 className="text-4xl lg:text-5xl font-bold leading-tight text-[#a4c4b5]">
Let's make some plans!
</h2>
<div className="text-gray-700 mt-8">
Want to send us an email? <br />
<a
className="underline text-sm"
href="mailto:[email protected]"
>
Click Here
</a>
</div>
</div>
<div className="mt-12 text-center ml-7 md:ml-0">
<img
src={"./assets/contact.jpg" || "https://dummyimage.com/720x600"}
alt="Contact"
className="w-[90%] rounded-xl"
/>
</div>
</div>
<form
className={`${
isResetting
? "animate-fadeOut" // Apply fade-out animation class when resetting
: "animate-fadeIn" // Apply fade-in animation class when displaying
} mt-8`}
onSubmit={formik.handleSubmit}
>
<div className="mt-8">
<label
htmlFor="name"
className="uppercase text-sm text-gray-600 font-bold"
>
Full Name
</label>
<input
autoComplete="off"
type="text"
id="name"
name="name"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="Enter your name"
className={`w-full bg-gray-200 text-gray-900 mt-2 p-3 border-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.name && formik.errors.name
? "border-red-500" // Add error border
: ""
}`}
required
/>
{formik.touched.name && formik.errors.name && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.name}
</div>
)}
</div>
<div className="mt-8">
<label
htmlFor="organisation"
className="uppercase text-sm text-gray-600 font-bold"
>
School / Organisation
</label>
<input
autoComplete="off"
type="text"
id="organisation"
name="organisation"
value={formik.values.organisation}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="Enter details"
className={`w-full bg-gray-200 border-2 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.organisation && formik.errors.organisation
? "border-red-500" // Add error border
: ""
}`}
required
/>
{formik.touched.organisation && formik.errors.organisation && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.organisation}
</div>
)}
</div>
<div className="mt-8 flex flex-col">
<label
htmlFor="location"
className="uppercase text-sm text-gray-600 font-bold"
>
Location
</label>
<select
id="location"
name="location"
value={formik.values.location}
onChange={formik.handleChange}
className={`w-full bg-gray-200 border-2 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.location && formik.errors.location
? "border-red-500" // Add error border
: ""
}`}
>
<option value="south-australia">South Australia</option>
<option value="queensland">Queensland</option>
<option value="western-australia">Western Australia</option>
</select>
{formik.touched.location && formik.errors.location && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.location}
</div>
)}
</div>
<div className="mt-8">
<label
htmlFor="email"
className="uppercase text-sm text-gray-600 font-bold"
>
Email
</label>
<input
autoComplete="off"
type="email"
id="email"
name="email"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="Enter your email address"
className={`w-full bg-gray-200 border-2 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.email && formik.errors.email
? "border-red-500" // Add error border
: ""
}`}
required
/>
{formik.touched.email && formik.errors.email && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.email}
</div>
)}
</div>
<div className="mt-8">
<label
htmlFor="number"
className="uppercase text-sm text-gray-600 font-bold"
>
Phone Number
</label>
<input
autoComplete="off"
type="tel"
id="number"
name="number"
value={formik.values.number}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="Enter your best contact number"
className={`w-full bg-gray-200 border-2 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.number && formik.errors.number
? "border-red-500" // Add error border
: ""
}`}
required
/>
{formik.touched.number && formik.errors.number && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.number}
</div>
)}
</div>
<div className="mt-8">
<label className="uppercase text-sm text-gray-600 font-bold">
Select Relevant:
</label>
<div className="mt-2">
<input
autoComplete="off"
type="checkbox"
id="design"
name="design"
checked={formik.values.design}
onChange={formik.handleChange}
className="mr-2 text-gray-600 font-bold"
/>
<label htmlFor="design">Design + Build</label>
</div>
<div>
<input
autoComplete="off"
type="checkbox"
id="maintenance"
name="maintenance"
checked={formik.values.maintenance}
onChange={formik.handleChange}
className="mr-2"
/>
<label htmlFor="maintenance">Maintenance</label>
</div>
<div>
<input
autoComplete="off"
type="checkbox"
id="repairs"
name="repairs"
checked={formik.values.repairs}
onChange={formik.handleChange}
className="mr-2"
/>
<label htmlFor="repairs">Repairs</label>
</div>
</div>
<div className="mt-8">
<label
htmlFor="message"
className="uppercase text-sm text-gray-600 font-bold"
>
Message
</label>
<textarea
id="message"
name="message"
value={formik.values.message}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="Enter your message - include as much information as possible"
className={`w-full h-32 bg-gray-200 border-2 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] ${
formik.touched.message && formik.errors.message
? "border-red-500" // Add error border
: ""
}`}
required
></textarea>
{formik.touched.message && formik.errors.message && (
<div className="text-red-500 text-sm mt-1">
{formik.errors.message}
</div>
)}
</div>
<div className="mt-8">
<button
type="submit"
className="uppercase text-sm font-bold tracking-wide bg-[#a4c4b5] text-gray-100 p-3 rounded-lg w-full focus:outline-none focus:ring-2 focus:ring-[#a4c4b5] hover:bg-[#94b4a5]"
disabled={formik.isSubmitting}
>
Send Message
</button>
</div>
</form>
<SuccessModal isOpen={isModalOpen} onClose={closeModal} />
</div>
);
};
export default ContactForm;
这是我的sendEmail.ts:
import nodemailer from "nodemailer";
interface FormData {
name: string;
organisation: string;
email: string;
location: string;
number: string;
message: string;
design: boolean;
maintenance: boolean;
repairs: boolean;
}
export async function sendMail(formData: FormData) {
try {
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.USER,
pass: process.env.PASS,
},
});
const mailOptions = {
from: `"${formData.name}" <${formData.email}>`,
to: "[email protected]", // Replace with the recipient's email address
subject: "Contact Form Submission",
html: `
<h2>Contact Form Submission</h2>
<p><strong>Name:</strong> ${formData.name}</p>
<p><strong>Organisation:</strong> ${formData.organisation}</p>
<p><strong>Location:</strong> ${formData.location}</p>
<p><strong>Phone Number:</strong> ${formData.number}</p>
<p><strong>Message:</strong> ${formData.message}</p>
<p><strong>Design:</strong> ${formData.design ? "Yes" : "No"}</p>
<p><strong>Maintenance:</strong> ${
formData.maintenance ? "Yes" : "No"
}</p>
<p><strong>Repairs:</strong> ${formData.repairs ? "Yes" : "No"}</p>
`,
};
const info = await transporter.sendMail(mailOptions);
console.log("Email Sent");
return true;
} catch (error) {
console.error("Error sending email:", error);
throw error;
}
}
这是我的文件夹结构:
- playground_guardians
- app
- .env.local
- favicon.ico
- globals.css
- layout.tsx
- page.tsx
- components
- Containers
- AboutContainer.tsx
- CardContainer.tsx
- FeaturedContainer.tsx
- About.tsx
- CardFeature.tsx
- CompanyName.tsx
- ContactForm.tsx
- Feature.tsx
- Footer.tsx
- Hero.tsx
- Mission.tsx
- Navbar.tsx
- SuccessModal.tsx
- node_modules
-pages
- api
- sendEmail.ts
- public
- .eslintrc.json
- .gitignore
- next-env.d.ts
- next.config.js
- package-lock.json
- package.json
- postcss.config.json
- README.md
- tailwind.configt.ts
- tsconfig.json
这是我第一次创建发送到电子邮件的联系表单,我在创建此类组件方面没有太多经验。
我收到 404 错误,但现在我收到此错误:
ContactForm.tsx:67 POST http://localhost:3000/api/sendEmail 500(内部服务器错误)
onSubmit @ ContactForm.tsx:67
eval @ formik.esm.js:956
eval @ formik.esm.js:1266
eval @ formik.esm.js:872
Promise.then(异步)
eval @ formik.esm.js:848
eval @ formik.esm.js:1266
eval @ formik.esm.js:936
eval @ formik.esm.js:1266
callcallback @ react-dom.development.js:20367
invokeGuardedCallbackImpl @ react-dom.development.js:20416
invokeGuardedCallback @ react-dom.development.js:20491
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:20505
executeDispatch @ react-dom.development.js:31842
进程调度队列项目顺序 @ react-dom.development.js:31874
进程调度队列 @ react-dom.development.js:31887
dispatchEventsForPlugins @ react-dom.development.js:31898
eval @ react-dom.development.js:32088
批处理更新$1 @ react-dom.development.js:24699
批处理更新 @ react-dom.development.js:28559
dispatchEventForPluginEventSystem @ react-dom.development.js:32087
调度事件 @ react-dom.development.js:29855
调度离散事件 @ react-dom.development.js:29826
app-index.js:31 发送电子邮件时出错
请帮忙
答: 暂无答案
评论