Реализация персонализированных email-рассылок на сайте

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация персонализированных email-рассылок на сайте
Средняя
~5 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка персонализированных email-кампаний

Персонализация выходит за рамки {{firstName}} — это разные блоки контента по сегментам, рекомендации товаров на основе истории, A/B варианты Subject Line, адаптация контента по языку и часовому поясу. Всё это требует кода на бэкенде и данных из CRM/аналитики.

Слои персонализации

Уровень 1 — базовые поля: Имя, компания, дата последнего визита. Простая подстановка через шаблонизатор.

Уровень 2 — сегментация: Разные блоки контента для разных групп пользователей.

Уровень 3 — поведенческие данные: Рекомендации на основе истории покупок/просмотров, персональные скидки на брошенные товары.

Уровень 4 — предиктивная персонализация: ML-модели для предсказания оптимального времени отправки и контента.

Сборка персонализированного письма

interface PersonalizationContext {
  user: User;
  segment: 'new' | 'active' | 'at_risk' | 'churned';
  recommendedProducts: Product[];
  lastViewedCategory: string;
  totalOrders: number;
  preferredLanguage: 'ru' | 'en';
  discount?: { code: string; percent: number; validUntil: Date };
}

async function buildPersonalizedEmail(
  userId: string,
  campaignId: string
): Promise<{ subject: string; html: string }> {
  // Собрать контекст из разных источников параллельно
  const [user, orders, recentViews, discount] = await Promise.all([
    db.users.findById(userId),
    db.orders.getRecentByUser(userId, 5),
    db.productViews.getRecentByUser(userId, 20),
    db.discounts.getPersonalDiscount(userId),
  ]);

  const segment = classifySegment(user, orders);
  const recommended = await recommendationEngine.getProducts(userId, recentViews);

  const ctx: PersonalizationContext = {
    user,
    segment,
    recommendedProducts: recommended.slice(0, 3),
    lastViewedCategory: recentViews[0]?.categoryName ?? '',
    totalOrders: orders.length,
    preferredLanguage: user.language ?? 'ru',
    discount: discount ?? undefined,
  };

  // Выбрать тему письма на основе сегмента
  const subjects: Record<PersonalizationContext['segment'], string> = {
    new: `${user.name}, вот что поможет вам начать`,
    active: `${user.name}, специально для вас — новинки в "${ctx.lastViewedCategory}"`,
    at_risk: `Мы скучаем, ${user.name}! Специальное предложение внутри`,
    churned: `${user.name}, вернитесь — скидка ${discount?.percent ?? 20}% ждёт вас`,
  };

  const html = render(<PersonalizedCampaign ctx={ctx} campaignId={campaignId} />);

  return { subject: subjects[segment], html };
}

Сегментация пользователей

function classifySegment(user: User, orders: Order[]): PersonalizationContext['segment'] {
  const daysSinceRegistration = daysBetween(user.createdAt, new Date());
  const daysSinceLastOrder = orders.length > 0
    ? daysBetween(orders[0].createdAt, new Date())
    : Infinity;

  if (daysSinceRegistration < 7) return 'new';
  if (daysSinceLastOrder < 30) return 'active';
  if (daysSinceLastOrder < 90) return 'at_risk';
  return 'churned';
}

React Email компонент с условным контентом

function PersonalizedCampaign({ ctx, campaignId }) {
  const { user, segment, recommendedProducts, discount } = ctx;

  return (
    <Html>
      <Preview>
        {segment === 'churned'
          ? `Скидка ${discount?.percent}% — только для вас`
          : `Новинки специально для ${user.name}`}
      </Preview>
      <Body>
        {/* Hero зависит от сегмента */}
        {segment === 'at_risk' || segment === 'churned' ? (
          <ReEngagementHero discount={discount} userName={user.name} />
        ) : (
          <StandardHero userName={user.name} />
        )}

        {/* Персональные рекомендации */}
        {recommendedProducts.length > 0 && (
          <Section>
            <Heading>Рекомендуем для вас</Heading>
            <Row>
              {recommendedProducts.map(product => (
                <Column key={product.id}>
                  <ProductCard
                    product={product}
                    utm={`utm_campaign=${campaignId}&utm_content=rec-${product.id}`}
                    discount={discount}
                  />
                </Column>
              ))}
            </Row>
          </Section>
        )}

        {/* Персональный промокод — только для at_risk и churned */}
        {discount && (segment === 'at_risk' || segment === 'churned') && (
          <Section style={{ background: '#fef3c7', padding: 24, borderRadius: 8 }}>
            <Text>Ваш персональный промокод:</Text>
            <Text style={{ fontSize: 28, fontWeight: 800, letterSpacing: 4 }}>
              {discount.code}
            </Text>
            <Text style={{ color: '#92400e' }}>
              Скидка {discount.percent}% до {formatDate(discount.validUntil)}
            </Text>
          </Section>
        )}

        <Footer unsubscribeUrl={generateUnsubscribeUrl(user.id)} />
      </Body>
    </Html>
  );
}

Оптимальное время отправки

// Анализируем историю открытий для определения лучшего времени
async function getOptimalSendTime(userId: string): Promise<Date> {
  const openHistory = await db.emailOpenEvents.getByUser(userId, 90);  // 90 дней

  if (openHistory.length < 5) {
    // Не хватает данных — использовать дефолт 10:00 по часовому поясу
    return getNextOccurrenceOfHour(10, userTimezone);
  }

  // Найти час с наибольшим числом открытий
  const hourCounts = openHistory.reduce((acc, event) => {
    const hour = new Date(event.openedAt).getHours();
    acc[hour] = (acc[hour] ?? 0) + 1;
    return acc;
  }, {} as Record<number, number>);

  const bestHour = Number(
    Object.entries(hourCounts).sort(([, a], [, b]) => b - a)[0][0]
  );

  return getNextOccurrenceOfHour(bestHour, userTimezone);
}

Сроки

Персонализированная кампания с сегментацией, рекомендациями и условным контентом — 1 неделя. С ML-моделью оптимального времени — ещё 3–5 дней.