send email when message is sent

This commit is contained in:
jackiettran
2025-11-10 13:05:10 -05:00
parent 3442e880d8
commit d8a927ac4e
3 changed files with 308 additions and 0 deletions

View File

@@ -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,

View File

@@ -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();

View File

@@ -0,0 +1,251 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>New Message from {{senderName}}</title>
<style>
/* Reset styles */
body, table, td, p, a, li, blockquote {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table, td {
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
-ms-interpolation-mode: bicubic;
}
/* Base styles */
body {
margin: 0;
padding: 0;
width: 100% !important;
min-width: 100%;
height: 100%;
background-color: #f8f9fa;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
color: #212529;
}
/* Container */
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Header */
.header {
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
padding: 40px 30px;
text-align: center;
}
.logo {
font-size: 32px;
font-weight: 700;
color: #ffffff;
text-decoration: none;
letter-spacing: -1px;
}
.tagline {
color: #d4edda;
font-size: 14px;
margin-top: 8px;
}
/* Content */
.content {
padding: 40px 30px;
}
.content h1 {
font-size: 24px;
font-weight: 600;
margin: 0 0 20px 0;
color: #212529;
}
.content h2 {
font-size: 20px;
font-weight: 600;
margin: 30px 0 15px 0;
color: #495057;
}
.content p {
margin: 0 0 16px 0;
color: #6c757d;
line-height: 1.6;
}
.content strong {
color: #495057;
}
/* Button */
.button {
display: inline-block;
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
color: #ffffff !important;
text-decoration: none;
padding: 16px 32px;
border-radius: 6px;
font-weight: 600;
margin: 20px 0;
text-align: center;
transition: all 0.3s ease;
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
}
/* Info box */
.info-box {
background-color: #e7f3ff;
border-left: 4px solid #0066cc;
padding: 20px;
margin: 20px 0;
border-radius: 0 6px 6px 0;
}
.info-box p {
margin: 0;
color: #004085;
}
/* Message box */
.message-box {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
padding: 20px;
margin: 20px 0;
border-radius: 6px;
}
.message-box .subject {
font-size: 16px;
font-weight: 600;
color: #495057;
margin: 0 0 15px 0;
}
.message-box .content-text {
color: #212529;
line-height: 1.6;
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
.message-box .timestamp {
font-size: 12px;
color: #6c757d;
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #dee2e6;
}
/* Footer */
.footer {
background-color: #f8f9fa;
padding: 30px;
text-align: center;
border-top: 1px solid #e9ecef;
}
.footer p {
margin: 0 0 10px 0;
font-size: 14px;
color: #6c757d;
}
.footer a {
color: #667eea;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
/* Responsive */
@media only screen and (max-width: 600px) {
.email-container {
margin: 0;
border-radius: 0;
}
.header, .content, .footer {
padding: 20px;
}
.logo {
font-size: 28px;
}
.content h1 {
font-size: 22px;
}
.button {
display: block;
width: 100%;
box-sizing: border-box;
}
.message-box {
padding: 15px;
}
}
</style>
</head>
<body>
<div class="email-container">
<div class="header">
<div class="logo">RentAll</div>
<div class="tagline">New Message</div>
</div>
<div class="content">
<p>Hi {{recipientName}},</p>
<h1>You have a new message from {{senderName}}</h1>
<p>{{senderName}} sent you a message on RentAll.</p>
<div class="message-box">
<div class="subject">Subject: {{subject}}</div>
<div class="content-text">{{messageContent}}</div>
<div class="timestamp">Sent {{timestamp}}</div>
</div>
<a href="{{conversationUrl}}" class="button">View Conversation</a>
<p>Click the button above to read and reply to this message on RentAll.</p>
<div class="info-box">
<p><strong>Tip:</strong> Reply quickly to keep your conversations active and build trust within the RentAll community.</p>
</div>
</div>
<div class="footer">
<p><strong>RentAll</strong></p>
<p>You received this email because you have an account on RentAll and someone sent you a message.</p>
<p>If you have any questions, please contact our support team.</p>
<p>&copy; 2024 RentAll. All rights reserved.</p>
</div>
</div>
</body>
</html>