I have a contact form that I want to automate to send validated user input to an email address. I’m not sure what’s wrong at this point but I feel as though I’m not using nodemailer correctly. These are the relevant code snippets. Btw I’m using live server and running the server on the same port to not have a cross origin problem. And these are the errors I get when I try to submit a sample form submission
I did a lot it’s basically all in the code, I used the CORS package to solve the possible cross origin problem. The createTransport code block is not what it was before as I changed it due to a recommendation of a friend who looked through nodemailers documentation. I managed to solve some console error messages but the biggest one being the 405 error I can’t seem to fix. I’ve tried everything at this point
Console error messages
server.mjs:7 Uncaught SyntaxError: Cannot use import statement outside a module
index.js:198 POST http://127.0.0.1:5500/api/submit-form net::ERR_ABORTED 405 (Method Not Allowed)
submitFormData @ index.js:198
(anonymous) @ index.js:232
setTimeout (async)
(anonymous) @ index.js:231
index.js:203 Response Status Code: 405
html
<section class="py-20">
<div class="flex justify-center items-center w-screen h-screen bg-white">
<div class="container mx-auto my-4 px-4 lg:px-20">
<form id="form" method="POST" class="w-full p-8 my-4 md:px-12 lg:w-9/12 lg:pl-20 lg:pr-40 mr-auto rounded-2xl shadow-2xl">
<div class="flex justify-center">
<h1 class="font-semibold text-5xl">Let Us Know What's On Your Mind</h1>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 mt-5">
<input id="fullName" autocomplete="off" required class="w-full bg-gray-200 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" type="text" placeholder="Full Name*"/>
<input id="subject" autocomplete="off" required class="w-full bg-gray-200 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" type="text" placeholder="Subject*"/>
<input id="emailAddress" autocomplete="off" required class="w-full bg-gray-200 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" type="email" placeholder="Email Address* (Proper format please)"/>
<input id="phoneNumber" autocomplete="off" type="tel" required class="w-full bg-gray-200 text-gray-900 mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline" placeholder="Phone Number* (Proper format please)"/>
</div>
<div class="my-4">
<textarea id="message" autocomplete="off" required placeholder="Message* (40 character minimum)" class="w-full h-40 bg-gray-200 text-gray mt-2 p-3 rounded-lg focus:outline-none focus:shadow-outline"></textarea>
</div>
<div class="my-2 gap-6 w-full lg:w-1/4 flex">
<button id="cancel" class="text-base font-bold tracking-wide bg-red-600 text-white p-3 rounded-lg w-full focus:outline-none focus:shadow-outline">Cancel</button>
<button style="background-color: rgb(21, 128, 61);" id="submit" type="submit" class="text-base font-bold tracking-wide text-white p-3 rounded-lg w-full focus:outline-none focus:shadow-outline">Submit</button>
</div>
</form>
</div>
</div>
</section>
index.js
const submitFormData = () => {
const formData = new FormData(form);
fetch('/api/submit-form', {
method: 'POST',
body: formData,
})
.then((res) => {
console.log('Response Status Code:', res.status);
if (res.ok) {
form.reset();
formSubmissionStatus.textContent = 'Form submitted successfully!';
formSubmissionStatus.classList.remove('bg-black');
formSubmissionStatus.style.backgroundColor = 'rgb(21, 128, 61)';
} else {
formSubmissionStatus.textContent = 'Form submission failed';
formSubmissionStatus.classList.remove('bg-black');
formSubmissionStatus.style.backgroundColor = '';
formSubmissionStatus.classList.add('bg-red-600');
}
})
.catch((error) => {
console.error('Fetch Error:', error);
formSubmissionStatus.textContent = 'An error occured, please try again.';
formSubmissionStatus.classList.add('bg-black', 'text-white-700');
});
};
form.addEventListener('submit', (e) => {
e.preventDefault();
if(formValidityCheck()) {
submitButton.disabled = true;
formSubmissionStatus.textContent = 'Submitting...';
formSubmissionStatus.classList.add('bg-black', 'text-white');
setTimeout(() => {
submitFormData();
}, 500);
}
});
server.mjs
import nodemailer from 'nodemailer';
import dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';
import { body, validationResult } from 'express-validator';
const port = process.env.PORT || 5500;
const app = express();
const corsOptions = {
origin: 'http://127.0.0.1:5500/',
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/api/submit-form', [
body('fullName').trim().isLength({ min: 2 }).escape(),
body('subject').trim().isLength({ min: 3 }).escape(),
body('emailAddress').trim().isEmail().normalizeEmail(),
body('phoneNumber').trim().isMobilePhone('any').escape(),
body('message').trim().isLength({ min: 40 }).escape(),
], async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const { fullName, subject, emailAddress, phoneNumber, message } = req.body;
const transporter = nodemailer.createTransport("SMTP",{
host: "smtp-mail.outlook.com",
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD
},
});
const mailOptions = {
from: process.env.EMAIL_FROM,
to: process.env.EMAIL_SENDER,
subject: `New Contact Form Submission! ${subject}`,
text: `Full Name: ${fullName}nEmail: ${emailAddress}nPhone: ${phoneNumber}nnMessage: ${message}`,
};
await transporter.sendMail(mailOptions);
res.status(200).json({ message: 'Form submitted successfully' });
console.log('Response Status Code:', 200);
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Internal server error'});
console.log('Response Status Code:', 500);
}
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});