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 ``,
}