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}} + + + +
+
+ +
New Message
+
+ +
+

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.

+
+
+ + +
+ +