From d8a927ac4e89f0b7a338da3a090507b38cbb19ca Mon Sep 17 00:00:00 2001
From: jackiettran <41605212+jackiettran@users.noreply.github.com>
Date: Mon, 10 Nov 2025 13:05:10 -0500
Subject: [PATCH] send email when message is sent
---
backend/routes/messages.js | 18 ++
backend/services/emailService.js | 39 +++
.../templates/emails/newMessageToUser.html | 251 ++++++++++++++++++
3 files changed, 308 insertions(+)
create mode 100644 backend/templates/emails/newMessageToUser.html
diff --git a/backend/routes/messages.js b/backend/routes/messages.js
index 8ce6e85..54cf384 100644
--- a/backend/routes/messages.js
+++ b/backend/routes/messages.js
@@ -4,6 +4,7 @@ const { authenticateToken } = require('../middleware/auth');
const logger = require('../utils/logger');
const { emitNewMessage, emitMessageRead } = require('../sockets/messageSocket');
const { Op } = require('sequelize');
+const emailService = require('../services/emailService');
const router = express.Router();
// Get all messages for the current user (inbox)
@@ -278,6 +279,23 @@ router.post('/', authenticateToken, async (req, res) => {
emitNewMessage(io, receiverId, messageWithSender.toJSON());
}
+ // Send email notification to receiver
+ try {
+ const sender = await User.findByPk(req.user.id, {
+ attributes: ['id', 'firstName', 'lastName', 'email']
+ });
+
+ await emailService.sendNewMessageNotification(receiver, sender, message);
+ } catch (emailError) {
+ // Log email error but don't block the message send
+ const reqLogger = logger.withRequestId(req.id);
+ reqLogger.error("Failed to send message notification email", {
+ error: emailError.message,
+ messageId: message.id,
+ receiverId: receiverId
+ });
+ }
+
const reqLogger = logger.withRequestId(req.id);
reqLogger.info("Message sent", {
senderId: req.user.id,
diff --git a/backend/services/emailService.js b/backend/services/emailService.js
index 5934019..441f0d4 100644
--- a/backend/services/emailService.js
+++ b/backend/services/emailService.js
@@ -54,6 +54,7 @@ class EmailService {
"alphaInvitationToUser.html",
"feedbackConfirmationToUser.html",
"feedbackNotificationToAdmin.html",
+ "newMessageToUser.html",
];
for (const templateFile of templateFiles) {
@@ -1849,6 +1850,44 @@ class EmailService {
htmlContent
);
}
+
+ async sendNewMessageNotification(receiver, sender, message) {
+ try {
+ const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
+ const conversationUrl = `${frontendUrl}/messages/conversations/${sender.id}`;
+
+ const timestamp = new Date(message.createdAt).toLocaleString("en-US", {
+ dateStyle: "medium",
+ timeStyle: "short",
+ });
+
+ const variables = {
+ recipientName: receiver.firstName || "there",
+ senderName: `${sender.firstName} ${sender.lastName}`.trim() || "A user",
+ subject: message.subject,
+ messageContent: message.content,
+ conversationUrl: conversationUrl,
+ timestamp: timestamp,
+ };
+
+ const htmlContent = this.renderTemplate("newMessageToUser", variables);
+
+ const subject = `New message from ${sender.firstName} ${sender.lastName}`;
+
+ const result = await this.sendEmail(receiver.email, subject, htmlContent);
+
+ if (result.success) {
+ console.log(
+ `Message notification email sent to ${receiver.email} from ${sender.email}`
+ );
+ }
+
+ return result;
+ } catch (error) {
+ console.error("Failed to send message notification email:", error);
+ return { success: false, error: error.message };
+ }
+ }
}
module.exports = new EmailService();
diff --git a/backend/templates/emails/newMessageToUser.html b/backend/templates/emails/newMessageToUser.html
new file mode 100644
index 0000000..8a1b092
--- /dev/null
+++ b/backend/templates/emails/newMessageToUser.html
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+ New Message from {{senderName}}
+
+
+
+
+
+
+
+
Hi {{recipientName}},
+
+
You have a new message from {{senderName}}
+
+
{{senderName}} sent you a message on RentAll.
+
+
+
Subject: {{subject}}
+
{{messageContent}}
+
Sent {{timestamp}}
+
+
+
View Conversation
+
+
Click the button above to read and reply to this message on RentAll.
+
+
+
Tip: Reply quickly to keep your conversations active and build trust within the RentAll community.
+
+
+
+
+
+
+