diff --git a/mail-service/src/controllers/trackingController.js b/mail-service/src/controllers/trackingController.js new file mode 100644 index 0000000..fcc175c --- /dev/null +++ b/mail-service/src/controllers/trackingController.js @@ -0,0 +1,72 @@ +import { DeliveryLog } from '../models/index.js'; + +export default { + async trackOpen(req, res) { + try { + const { deliveryLogId } = req.params; + + // Находим запись в DeliveryLog + const deliveryLog = await DeliveryLog.findByPk(deliveryLogId); + + if (!deliveryLog) { + return res.status(404).send('Not found'); + } + + // Обновляем время открытия, если еще не было установлено + if (!deliveryLog.opened_at) { + await deliveryLog.update({ + opened_at: new Date() + }); + console.log(`[Tracking] Email opened: deliveryLogId=${deliveryLogId}, campaignId=${deliveryLog.campaign_id}, subscriberId=${deliveryLog.subscriber_id}`); + } + + // Возвращаем прозрачный 1x1 пиксель + const pixel = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==', 'base64'); + res.writeHead(200, { + 'Content-Type': 'image/png', + 'Content-Length': pixel.length, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + }); + res.end(pixel); + + } catch (err) { + console.error('[Tracking] Error tracking email open:', err); + res.status(500).send('Error'); + } + }, + + async trackClick(req, res) { + try { + const { deliveryLogId } = req.params; + const { url } = req.query; + + if (!url) { + return res.status(400).send('URL parameter required'); + } + + // Находим запись в DeliveryLog + const deliveryLog = await DeliveryLog.findByPk(deliveryLogId); + + if (!deliveryLog) { + return res.status(404).send('Not found'); + } + + // Обновляем время клика, если еще не было установлено + if (!deliveryLog.clicked_at) { + await deliveryLog.update({ + clicked_at: new Date() + }); + console.log(`[Tracking] Email clicked: deliveryLogId=${deliveryLogId}, campaignId=${deliveryLog.campaign_id}, subscriberId=${deliveryLog.subscriber_id}, url=${url}`); + } + + // Перенаправляем на оригинальный URL + res.redirect(url); + + } catch (err) { + console.error('[Tracking] Error tracking email click:', err); + res.status(500).send('Error'); + } + } +}; \ No newline at end of file diff --git a/mail-service/src/routes/index.js b/mail-service/src/routes/index.js index b95d241..e82580c 100644 --- a/mail-service/src/routes/index.js +++ b/mail-service/src/routes/index.js @@ -8,6 +8,7 @@ import campaignRoutes from './campaign.js'; import deliveryLogRoutes from './deliveryLog.js'; import smtpServerRoutes from './smtpServer.js'; import topicRoutes from './topic.js'; +import trackingRoutes from './tracking.js'; const router = Router(); @@ -20,5 +21,6 @@ router.use('/campaigns', campaignRoutes); router.use('/delivery-logs', deliveryLogRoutes); router.use('/smtp-servers', smtpServerRoutes); router.use('/topics', topicRoutes); +router.use('/track', trackingRoutes); export default router; \ No newline at end of file diff --git a/mail-service/src/routes/tracking.js b/mail-service/src/routes/tracking.js new file mode 100644 index 0000000..c05aad8 --- /dev/null +++ b/mail-service/src/routes/tracking.js @@ -0,0 +1,12 @@ +import express from 'express'; +import trackingController from '../controllers/trackingController.js'; + +const router = express.Router(); + +// Трекинг открытия письма +router.get('/open/:deliveryLogId', trackingController.trackOpen); + +// Трекинг клика по ссылке +router.get('/click/:deliveryLogId', trackingController.trackClick); + +export default router; \ No newline at end of file diff --git a/mail-service/src/service/dynamicConsumer.js b/mail-service/src/service/dynamicConsumer.js index eb73f4c..e76e8b9 100644 --- a/mail-service/src/service/dynamicConsumer.js +++ b/mail-service/src/service/dynamicConsumer.js @@ -259,12 +259,26 @@ async function processEmailTask(task, topic) { }); console.log(`[DynamicConsumer] Transporter created successfully`); + // Добавляем трекинг-пиксель для отслеживания открытия письма + const trackingPixel = ``; + + // Обрабатываем ссылки для отслеживания кликов + const htmlWithClickTracking = task.html.replace( + / { + const trackingUrl = `http://${smtp.from_email}/api/mail/track/click/${deliveryLog.id}?url=${encodeURIComponent(url)}`; + return ``, }