I have a React App running at port 44411 and react-email at port 3000.
I have watched a youtube vid on how to set up react-email and resend but it inmediately didn't work. So after fiddling with it alot I got it to take my API request through postman so the next step was to make it work through the website. I enabled CORS (Which also caused postman requests to not work anymore), and tried sending it through website (API request sent from 44411 tries fetching at 3000) which triggers this error:
Access to fetch at 'http://localhost:3000/api/email' from origin 'https://localhost:44411' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
ContactForm.js:30
POST http://localhost:3000/api/email net::ERR_FAILED
handleSubmit @ ContactForm.js:30
callCallback @ react-dom.development.js:3706
invokeGuardedCallbackDev @ react-dom.development.js:3750
invokeGuardedCallback @ react-dom.development.js:3807
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:3821
executeDispatch @ react-dom.development.js:7964
processDispatchQueueItemsInOrder @ react-dom.development.js:7990
processDispatchQueue @ react-dom.development.js:8001
dispatchEventsForPlugins @ react-dom.development.js:8010
(anonymous) @ react-dom.development.js:8170
batchedUpdates$1 @ react-dom.development.js:22559
batchedUpdates @ react-dom.development.js:3554
dispatchEventForPluginEventSystem @ react-dom.development.js:8169
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:5676
dispatchEvent @ react-dom.development.js:5670
dispatchDiscreteEvent @ react-dom.development.js:5647
Show 15 more frames
Show less
ContactForm.js:55 Error during fetch: TypeError: Failed to fetch
at handleSubmit (ContactForm.js:30:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3706:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3750:1)
at invokeGuardedCallback (react-dom.development.js:3807:1)
at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:3821:1)
at executeDispatch (react-dom.development.js:7964:1)
at processDispatchQueueItemsInOrder (react-dom.development.js:7990:1)
at processDispatchQueue (react-dom.development.js:8001:1)
at dispatchEventsForPlugins (react-dom.development.js:8010:1)
at react-dom.development.js:8170:1
And when I enabled CORS and sent a request through postman, these errors started coming up in my email console
⨯ TypeError: res.setHeader is not a function
at applyHeaders (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:149:25)
at applyHeaders (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:145:21)
at applyHeaders (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:145:21)
at cors (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:179:13)
at eval (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:213:33)
at originCallback (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:204:29)
at eval (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:208:25)
at optionsCallback (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:190:17)
at corsMiddleware (webpack-internal:///(rsc)/./node_modules/cors/lib/index.js:194:13)
at POST (webpack-internal:///(rsc)/./src/app/api/email/route.ts:25:5)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:63257
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\lib\trace\tracer.js:133:36
at NoopContextManager.with (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:7062)
at ContextAPI.with (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:518)
at NoopTracer.startActiveSpan (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:18093)
at ProxyTracer.startActiveSpan (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:18854)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\lib\trace\tracer.js:122:103
at NoopContextManager.with (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:7062)
at ContextAPI.with (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\@opentelemetry\api\index.js:1:518)
at NextTracerImpl.trace (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\lib\trace\tracer.js:122:28)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:56774
at AsyncLocalStorage.run (node:async_hooks:346:14)
at Object.wrap (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:37057)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:54547
at AsyncLocalStorage.run (node:async_hooks:346:14)
at Object.wrap (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:36306)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:54509
at AsyncLocalStorage.run (node:async_hooks:346:14)
at eH.execute (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53902)
at eH.handle (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:64515)
at doRender (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:1330:60)
at cacheEntry.responseCache.get.routeKind (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:1552:34)
at ResponseCache.get (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\response-cache\index.js:49:26)
at DevServer.renderToResponseWithComponentsImpl (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:1460:53)
at C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:990:121
at NextTracerImpl.trace (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\lib\trace\tracer.js:104:20)
at DevServer.renderToResponseWithComponents (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:990:41)
at DevServer.renderPageComponent (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:1843:35)
at async DevServer.renderToResponseImpl (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:1881:32)
at async DevServer.pipeImpl (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:909:25)
at async NextNodeServer.handleCatchallRenderRequest (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\next-server.js:266:17)
at async DevServer.handleRequestImpl (C:\Users\renek\source\ReactNet\ReactNet\ClientApp\.react-email\node_modules\next\dist\server\base-server.js:805:17)
This is my route.ts located in ReactNet\ReactNet\ClientApp.react-email\src\app\api\email
import { NextApiRequest, NextApiResponse } from 'next';
import Cors from 'cors';
import { Resend } from 'resend';
import Email from '../../../../emails/ContactEmail';
import AdminEmail from '../../../../emails/Email';
// Create CORS middleware
const corsMiddleware = Cors({
origin: 'http://localhost:44411', // Update this with your React app's URL
methods: ['POST'],
});
const resend = new Resend(process.env.RESEND_API_KEY || "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
// Export a function for the POST method
export async function POST(req: NextApiRequest, res: NextApiResponse) {
// Apply the CORS middleware
corsMiddleware(req, res, async () => {
try {
const { name, message, email, phone, workType } = req.body;
await resend.emails.send({
from: 'onboarding@resend.dev',
to: email,
subject: 'TedSite.nl - Bevestiging Contact Aanvraag',
react: Email({
name,
}),
});
await resend.emails.send({
from: 'onboarding@resend.dev',
to: "renekukske@gmail.com",
subject: 'TedSite.nl - Contact Aanvraag',
react: AdminEmail({
name,
message,
email,
phone,
workType,
}),
});
res.status(200).json({
status: 'Ok',
});
} catch (e: unknown) {
if (e instanceof Error) {
console.log(`Failed to send email: ${e.message}`);
}
res.status(500).json({
error: 'Internal server error.',
});
}
});
}
And this is my handleSubmit function
// Event handler for form submission
const handleSubmit = async (e) => {
e.preventDefault();
const { name, email, phone, workType, message } = formData;
console.log('Submitting data:', { name, email, phone, workType, message });
try {
const response = await fetch('http://localhost:3000/api/email', {
method: 'POST',
mode: "cors", // Change the mode to CORS
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name,
email,
phone,
workType,
message,
}),
});
if (!response.ok) {
// Handle non-successful response status
console.error(`HTTP error! Status: ${response.status}`);
// You can throw an error or handle it in another way
} else {
// Success
const data = await response.json();
console.log('Server response:', data);
// Handle success if needed
}
} catch (error) {
console.error('Error during fetch:', error);
// Handle errors that occur during the fetch itself
}
};
I hope someone knows how to help me.
Thanks in advance!
Bobbie
After fiddling with it some more for 3 days I have learned that:
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "https://localhost:44411" }, // replace this your actual origin
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
},
const response = await fetch('http://localhost:3000/api/email', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify(formData),
credentials: 'include',
mode: 'cors',
});
if (request.method === 'OPTIONS') {
// Handling preflight request
return NextResponse.json({ status: 200 });
}
const res = NextResponse.next()
// add the CORS headers to the response
res.headers.append('Access-Control-Allow-Credentials', "true")
res.headers.append('Access-Control-Allow-Origin', 'https://localhost:44411') // replace this your actual origin
res.headers.append('Access-Control-Allow-Methods', 'GET,PATCH,POST')
res.headers.append(
'Access-Control-Allow-Headers',
'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
)
I hope with these answers I can help someone in the future. Setting the Content-Type is what did the trick for me in the end.