I have deployed my website on cloudflare.
I want to send an email with nodemailer. It works locally, but fails in production. In production it gives me “405 – method not allowed”.
Initially I thought my env vriables are not set up correctly, however, I printed them and it seems they are with the correct values (in production!)
My project structure:
From my website/betatesting I call the following:
import { sendEmail } from '@/utils/send-email';
...
async function onSubmit(data: FormData, event) {
event.preventDefault();
try {
await sendEmail(data, setEmailSent, setError);
} catch (error) {
setError(true);
console.error(error)
}
}
Then on my sendEmail from @/utils/send-email:
import { FormData } from ‘react’;
import Error from ‘next/error’
import { type NextRequest, NextResponse } from ‘next/server’;
export async function sendEmail(data: FormData, setEmailSent, setError) {
console.log("SEND EMAIL function: ", data); //prints correct values
console.log("my email: ", process.env.NEXT_PUBLIC_MY_EMAIL); //prints correct values
console.log("pass: ", process.env.NEXT_PUBLIC_MY_PASSWORD); //prints correct values
const apiEndpoint = '/api/email/';
console.log("api endpoint: ", apiEndpoint); //prints correct values
const res = await fetch(apiEndpoint, {
method: 'POST',
body: JSON.stringify(data),
}) //FAILS HERE!!!!!!
if(res.status === 200){
setEmailSent(true);
}else{
setError(true);
}
}
My app/api/email/route.ts file:
import { type NextRequest, NextResponse } from 'next/server';
import nodemailer from 'nodemailer';
import Mail from 'nodemailer/lib/mailer';
export async function POST(request: NextRequest) {
console.log("MY WEBSITE DOES NOT REACH THIS PART IN PRODUCTION")
const { email, name, message, android, ios } = await request.json();
const transport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.NEXT_PUBLIC_MY_EMAIL,
pass: process.env.NEXT_PUBLIC_MY_PASSWORD,
},
});
const mailOptions: Mail.Options = {
from: process.env.NEXT_PUBLIC_MY_EMAIL,
to: process.env.NEXT_PUBLIC_MY_EMAIL,
// cc: email, (uncomment this line if you want to send a copy to the sender)
subject: `Message from ${name} (${email})`,
text: `Message content ${message}, ANDROID: ${android}, IOS: ${ios}`,
};
const sendMailPromise = () =>
new Promise<string>((resolve, reject) => {
transport.sendMail(mailOptions, function (err) {
if (!err) {
resolve('Email sent');
} else {
reject(err.message);
}
});
});
try {
await sendMailPromise();
return NextResponse.json({ message: 'Email sent' });
} catch (err) {
return NextResponse.json({ error: err }, { status: 500 });
}
}
Again, it works locally, it fails in production. Any ideas, why or how to fix it, much appreciated!