I have a portfolio using React + NextJS as frontend and Python + Django as backend for the email functionality... On the frontend i have a contact page where the visitor must complete a contact from with name, email, subject and message... on Local server is working fine, i receive the mail in the inbox but on Live server i'm getting an error but in the inspect element within the Network tab the status is 200 OK.. only difference is that the content-type on local is application/json and on Live server is text/plain and i don't know why...
This is the views.py :
from django.core.mail import EmailMessage
from django.http import JsonResponse
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
import json
import logging
# Set up logging
logger = logging.getLogger(__name__)
@csrf_exempt
def send_email(request):
try:
if request.method == 'POST':
data = json.loads(request.body)
subject = data['subject']
sender_email = data['email'] # Email provided in the form
sender_name = data['name'] # Name provided in the form
# Construct the message to include sender's details
message = f"Name: {sender_name}\nEmail: {sender_email}\n\n{data['message']}"
email = EmailMessage(
subject,
message,
settings.EMAIL_HOST_USER,
['[email protected]'],
headers={'Reply-To': sender_email}
)
email.send()
return JsonResponse({'status': 'Success', 'message': 'Email sent successfully.'}, content_type='application/json')
else:
return JsonResponse({'status': 'Invalid request'}, status=400)
except Exception as e:
# Log the error
logger.exception("An error occurred when trying to send an email:")
# Return a JSON response with the error message and a 500 status code
return JsonResponse({'status': 'Error', 'message': str(e)}, status=500)
This code is from local.. on Live server only the @csrf_exempt is removed from the code... the settings.py is configured properly and also this is the frontend contact page :
import React, { useState } from "react";
import Circles from "/components/Circles";
import Bulb from "../../components/Bulb";
import { BsArrowRight, BsDownload } from "react-icons/bs";
import { motion } from "framer-motion";
import { fadeIn } from "../../variants";
const Contact = () => {
const [formData, setFormData] = useState({
name: "",
email: "",
subject: "",
message: "",
});
const [submitStatus, setSubmitStatus] = useState({
submitted: false,
success: false,
message: "",
});
// Inline styles for the notification message
const notificationStyle = {
display: "block", // Use block to take up the full width
color: "#fff",
padding: "20px",
borderRadius: "5px",
textAlign: "center", // Center the text horizontally
zIndex: "10", // Ensure it's on top of other elements
marginBottom: "20px", // Space before the form starts
};
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleSubmit = async (event) => {
event.preventDefault();
// Check if all the form data is non-empty
const isFormValid =
formData.name.trim() &&
formData.email.trim() &&
formData.subject.trim() &&
formData.message.trim();
// If the form data is not valid, update the submitStatus with an error message and return early
if (!isFormValid) {
setSubmitStatus({
submitted: true,
success: false,
message: "Please fill in all the fields.",
});
return;
}
setSubmitStatus({ ...submitStatus, submitted: false }); // Reset the submit status on new submission
// Get the CSRF token
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie("csrftoken");
try {
const response = await fetch(
"http://127.0.0.1:8000/api/send_email/",
{
method: "POST",
headers: {
"Content-Type": "application/json",
// Include the CSRF token in the request header
"X-CSRFToken": csrftoken,
},
body: JSON.stringify(formData),
}
);
if (response.ok) {
const jsonResponse = await response.json();
setSubmitStatus({
submitted: true,
success: true,
message:
"Your message has been sent successfully. Thank you for reaching out!",
});
// Reset form
setFormData({
name: "",
email: "",
subject: "",
message: "",
});
} else {
setSubmitStatus({
submitted: true,
success: false,
message:
"There was an issue sending your message. Please try again later.",
});
}
} catch (error) {
setSubmitStatus({
submitted: true,
success: false,
message: "An error occurred. Please try again later.",
});
}
};
return (
<div className="h-full bg-primary/30">
<Circles />
<div className="container mx-auto py-32 text-center xl:text-left flex items-center justify-center h-full">
<div className="flex flex-col w-full max-w-[700px]">
<motion.h2
variants={fadeIn("up", 0.2)}
initial="hidden"
animate="show"
exit="hidden"
className="h2 text-center mb-12"
>
Let's <span className="text-accent">connect.</span>
</motion.h2>
{/* Form starts here */}
<motion.form
variants={fadeIn("up", 0.4)}
initial="hidden"
animate="show"
exit="hidden"
className="flex-1 flex flex-col gap-6 w-full mx-auto"
onSubmit={handleSubmit}
>
<div className="flex gap-x-6 w-full">
<input
type="text"
name="name"
placeholder="Name"
className="input"
value={formData.name}
onChange={handleChange}
/>
<input
type="email"
name="email"
placeholder="Email"
className="input"
value={formData.email}
onChange={handleChange}
/>
</div>
<input
type="text"
name="subject"
placeholder="Subject"
className="input"
value={formData.subject}
onChange={handleChange}
/>
<textarea
name="message"
placeholder="Message"
className="textarea"
value={formData.message}
onChange={handleChange}
></textarea>
<div className="flex justify-between">
<button
type="submit"
className="btn rounded-full border border-white/50 max-w-[170px] px-8 transition-all duration-300 flex items-center justify-center overflow-hidden hover:border-accent group"
>
<span className="group-hover:-translate-y-[120%] group-hover:opacity-0 transition-all duration-500">
Let's talk
</span>
<BsArrowRight className="-translate-y-[120%] opacity-0 group-hover:flex group-hover:-translate-y-0 group-hover:opacity-100 transition-all duration-300 absolute text-[22px]" />
</button>
<a
href="/CV.pdf"
download
className="btn rounded-full border border-white/50 max-w-[170px] px-8 transition-all duration-300 flex items-center justify-center overflow-hidden hover:border-accent group"
>
<span className="group-hover:-translate-y-[120%] group-hover:opacity-0 transition-all duration-500 flex items-center">
Resume
<BsDownload className="ml-2" />
</span>
<span className="-translate-y-[120%] opacity-0 group-hover:flex group-hover:-translate-y-0 group-hover:opacity-100 transition-all duration-300 absolute">
Download
</span>
</a>
</div>
{/* Notification message */}
{submitStatus.submitted && (
<div style={notificationStyle}>{submitStatus.message}</div>
)}
</motion.form>
</div>
</div>
<Bulb />
</div>
);
};
export default Contact;
This is also from local, only thing that i modify for Live server is the fetch address with the real domain...