diff --git a/package-lock.json b/package-lock.json index e32526e..9798239 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "lenis": "^1.3.23", "maath": "^0.10.8", "next": "16.2.6", + "nodemailer": "^9.0.0", "react": "19.2.4", "react-dom": "19.2.4", "react-leaflet": "^5.0.0", @@ -31,6 +32,7 @@ "@types/jest": "^30.0.0", "@types/leaflet": "^1.9.21", "@types/node": "^20", + "@types/nodemailer": "^8.0.1", "@types/react": "^19", "@types/react-dom": "^19", "@types/three": "^0.184.0", @@ -3045,6 +3047,16 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/nodemailer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.1.tgz", + "integrity": "sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/offscreencanvas": { "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", @@ -9018,6 +9030,15 @@ "node": ">=18" } }, + "node_modules/nodemailer": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.0.tgz", + "integrity": "sha512-tbPTid7d/p9jAA8CRZ3iomvrMaST0o6NYuY7v6JQZHpPRZ61mLFSPKYd7342NtOFuej9/+L48SOIxwfu2uDvtw==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/package.json b/package.json index 44a5c91..d31b392 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "lenis": "^1.3.23", "maath": "^0.10.8", "next": "16.2.6", + "nodemailer": "^9.0.0", "react": "19.2.4", "react-dom": "19.2.4", "react-leaflet": "^5.0.0", @@ -36,6 +37,7 @@ "@types/jest": "^30.0.0", "@types/leaflet": "^1.9.21", "@types/node": "^20", + "@types/nodemailer": "^8.0.1", "@types/react": "^19", "@types/react-dom": "^19", "@types/three": "^0.184.0", diff --git a/src/actions/sendEmail.ts b/src/actions/sendEmail.ts new file mode 100644 index 0000000..7dd8c78 --- /dev/null +++ b/src/actions/sendEmail.ts @@ -0,0 +1,53 @@ +"use server"; + +import nodemailer from "nodemailer"; + +export async function sendContactEmail(data: { + fullName: string; + email: string; + subject: string; + message: string; +}) { + const { fullName, email, subject, message } = data; + + if (!fullName || !email || !subject || !message) { + return { success: false, error: "All fields are required." }; + } + + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: Number(process.env.SMTP_PORT) || 465, + secure: true, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASSWORD, + }, + }); + + try { + await transporter.sendMail({ + from: `"${fullName}" <${process.env.SMTP_USER}>`, + to: process.env.CONTACT_RECEIVER, + replyTo: email, + subject: `New Contact Form Submission: ${subject}`, + html: ` +
Name: ${fullName}
+Email: ${email}
+Subject: ${subject}
+Message:
++ ${message.replace(/\n/g, "+
")} +