I have a Node/Express server just for send emails with nodemailer from a contact form just using fetch.
When I press submit, the request times out and I finally get the error on my client side browser: "No 'Access-Control-Allow-Origin' header is present on the requested resource."
But on my server, I require cors and use it. I have used it without options specified, with the wildcard origin of "*" and with the origin of my site. It does send the emails but the client cannot receive the success status code.
Can anyone help with this?
Server:
const cors = require('cors')
app.use(cors())
//post route and email stuff works fine.
Client:
async function sendEmail(address, subject, body){
try {
let response = await fetch('mysiteURL',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
emailAddress: address,
emailSubject: subject,
emailBody: body
})
})
if(response.ok){
console.log('email sent okay')
} else{
console.log('Email failed to send.')
}
console.log(response.json())
} catch (error) {
console.log('Email failed to send.')
}
}
Edit: Here's my full server side code
const express = require('express')
const http = require('http')
const cors = require('cors')
require('dotenv').config()
const mailer = require('nodemailer')
const app = express()
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(cors({
origin: "*"
}))
//email middleware
const transporter = mailer.createTransport({
service: "gmail",
auth: {
user: process.env.GAU,
pass: process.env.GAP
}
})
async function sendEmail(emailAddress, emailSubject, emailBody, from="site"){
const options = { timeZone: 'America/Chicago', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' };
const currentDate = new Date().toLocaleString('en-US', options);
let message = "<h1>"+emailSubject+"</h1>"
message += "<p>Email from contact form on myname."+from+"</p>"
message += "<br><br>"
message += "<h2>" + emailBody + "</h2>"
message += "<br><br>"
message += "<p>Reply to: "+emailAddress+"</p>"
message += "<br><br>"
message += "<p>At: "+currentDate+"</p>"
const mailOptions = {
form: process.env.GAU,
to: process.env.CONTACT_EMAIL,
subject: emailSubject + " | Contact Form",
html: message
}
const mailOptions2 = {
form: process.env.GAU,
to: emailAddress,
subject: "Thank you for reaching out!",
html: "<em>Thank you for reaching out!</em><br><br>"+message
}
let successful = true
transporter.sendMail(mailOptions, (error, info)=>{
if(error){
console.log('Error', error)
successful = false
}
else{
console.log("Email sent: ", info.response)
}
})
transporter.sendMail(mailOptions2, (error, info)=>{
if(error){
console.log('Error', error)
successful = false
}
else{
console.log("Email sent: ", info.response)
}
})
return successful
}
//routes
app.get('/', (req,res)=>{
res.json('test ok')
})
app.post("/sendEmailFromSiteForm",(req,res)=>{
const {
emailAddress, emailSubject, emailBody
} = req.body
try {
let result = sendEmail(emailAddress, emailSubject, emailBody, "site")
if(result) res.status(200)
else res.status(500)
} catch (error) {
res.status(500)
}
})
app.post("/sendEmailFromWorkForm",(req,res)=>{
const {
emailAddress, emailSubject, emailBody
} = req.body
try {
let result = sendEmail(emailAddress, emailSubject, emailBody, "work")
if(result) res.status(200)
else res.status(500)
} catch (error) {
res.status(500).json(error)
}
})
app.listen(8080 , ()=>{
'Server started on port 8080.'
})
I've been making little tweaks to try to get it work, so it's a little weird. The "site" or "work" specification is just because I will have the contact form at my myname.site website and my myname.work website, so it will just let me know which site's contact form it's coming from.
I've found the wrong parts in your API code. Well, honestly, there are a few of wrong parts but let me point the most critical part.
res.status(200)
is just indicating that your response code will be okay but it's not yet finalizing your request. with res.send()
method, you finally finish your http request and respond with result.
Please try with the below snippets.
//routes
app.get('/', (req,res)=>{
res.json('test ok')
})
app.post("/sendEmailFromSiteForm",(req,res)=>{
const {
emailAddress, emailSubject, emailBody
} = req.body
try {
let result = sendEmail(emailAddress, emailSubject, emailBody, "site")
if(result) res.status(200).send("okay")
else res.status(500).send("error")
} catch (error) {
res.status(500).send("error")
}
})
app.post("/sendEmailFromWorkForm",(req,res)=>{
const {
emailAddress, emailSubject, emailBody
} = req.body
try {
let result = sendEmail(emailAddress, emailSubject, emailBody, "work")
if(result) res.status(200).send("okay")
else res.status(500).send("error")
} catch (error) {
res.status(500).send("error")
}
})
app.listen(8080 , ()=>{
'Server started on port 8080.'
})