Блог Sendsay

Пишем про email-маркетинг. Показываем, как превратить email в эффективный маркетинговый канал.

Как определить лучшее время для рассылки

Даем советы и рекомендации. Предлагаем алгоритм расчета времени от аналитика.

Универсального, «золотого» времени для рассылки мы не назовем, его не существует. Любые предположения, теории и даже данные исследований применимы к конкретной целевой аудитории — не факт, что они сработают на ваших подписчиках. Мы расскажем об общих правилах и покажем, как вычислить время для своей аудитории с помощью специального алгоритма — это куда эффективнее.

Общие правила

Эти правила получены в ходе исследований — они подходят большинству, но не всем и уж точно не являются руководством к действию. Возьмите их на заметку, протестируйте, сравните результаты с предыдущими показателями. Если конверсия растет — отлично, если падает — возвращайтесь к предыдущей стратегии или пробуйте другую.

— Не отправляйте рассылки в понедельник утром

Ящик подписчика завален письмами, полученными за выходные. Как вариант, он еще не разобрал пятничную рабочую почту, а тут еще и новые задачи подоспели — ему не до вас.

— Не отправляйте маркетинговые рассылки в рабочие дни с 12:00 до 15:00

В это время работают, и если открывают, то скорее корпоративную почту. Сценарий «открыл письмо, перешел по ссылке, выбрал и купил» не прокатит. Все-таки выбирать новое платье в офисе, в середине рабочего дня — на это способны немногие.

— Экспериментируйте с рассылками на выходных

Предугадать результат в субботу и воскресенье сложно. При этом показатели по конверсии всегда удивляют — как с лучшей, так и с худшей стороны. Попробуйте, вдруг для вашей аудитории — это самое оно.

Отправляйте рассылки во вторник, среду и четверг. Исследования показывают, что по ссылкам чаще кликают во вторник, с 10 до 11 утра. Для маркетинговой рассылки подходит период с 15:00 до 17:00, а для афиш с развлекательными мероприятиями — вечер, с 17:00 до 19:00.

Работа с текущими показателями

Перед тем, как определить лучшее время для рассылки — посмотрите текущую статистику по open rate и click rate. Сравните ее с общими правилами и определите, соответствуют ли показатели и стоит ли следовать рекомендациям экспертов.

Покажем на собственном примере. Это статистика по рассылкам через нашу платформу:

На графике видно, что показатели понедельника превосходят показатели среды — это идет вразрез со статистикой глобальных исследований. И пусть вас не смущает 1% разницы, для крупной базы — это серьезный показатель.

Выводов пока не делаем, смотрим статистику по кликам:

Ситуация изменилась, понедельник сдал позиции — данные о несостоятельности этого дня подтвердились. Ну и мы помним, что открытое письмо неравно «прочитанному». Скорее всего, в начале дня его посмотрели и сразу же удалили, чтобы очистить «пространство» для новой рабочей недели. Целевого действия, как такового, нет.

Учитывайте общие правила, но всегда проверяйте их «на себе» — вполне возможно, что с вашими подписчиками эти правила не работают. Анализируя статистику, обращайте внимание не только на открытия, но и на клики.

Алгоритм для расчета оптимального времени рассылки

Способ, опять же, не универсальный. Он подойдет тем, чью базу можно назвать большой ( > 10 000 подписчиков), а рассылки — стабильными и постоянными ( > 200 выпусков за год). Если вы только начинаете и отправляйте письма от случая к случаю — воспользуйтесь общими правилами.

Теперь к самому интересному. Рассмотрим такой кейс:

Ваша таблица будет выглядеть примерно так:

Модифицируем таблицу:

  1. Вместо даты отправки создаем отдельно два столбца: день недели и час отправки
  2. Проделываем то же самое со временем прочтения и временем кликов
  3. Создаем параметр продолжительности «ожидания» перед прочтением кликов в минутах
  4. Оставляем только те выпуски, в которых участвовало большое количество подписчиков. Ориентируйтесь на 10-20% от общего числа.

Теперь таблица выглядит так:

После этого организуем таблицу, куда запишем статистические результаты:

Рассчитываем:

— Пропорции количества выпусков

Количество выпусков в конкретной ячейке, деленное на количество всех выпусков.

— Пропорции количества участников

Количество участников в конкретной ячейке, деленное на сумму всех участников в столбце.

— Вес «успешности» дня недели и отдельно часа

Агрегированные показатели по дням и часам: X × open.rate + (1 - X) × click.rate. За X можно взять показатель в 0.3.

— Вес средней читаемости и кликабельности

Open.rate (click.rate) × пропорция количества выпусков × пропорция количества участников выпуска.

— Итоговую «успешность»

Вес средней читаемости и кликабельности × вес «успешности» дня недели × вес «успешности» часа.

Полученный результат сортируем по убыванию и отбираем ТОП N строк, в которых и будут значения, которых мы добивались. То же самое можно сделать по сегменту клиентов — для этого на этапе подготовке данных отберите только те id клиентов, которые вам необходимы. Если учесть тестовые данные, указанные выше, то результат выглядит так:

С помощью этой таблицы вы выясните результативность рассылок, анализируя и сопоставляя день недели со временем выпуска. Когда лучшее время для отправки выяснено — работаем дальше: рассылаем, экспериментируем, улучшаем контент и углубляем персонализацию.

Как реализовать алгоритм в языке программирования R

Анализировать показатели можно в Excel и Google Spreadsheets. Одна проблема — количество строк в этих сервисах ограничено, поэтому с большим объемом информации они не справятся. Если работаете с крупными базами — рекомендуем освоить язык программирования R, хотя бы на минимальном уровне. Кроме того, базовые знания R упростят анализ данных из Google Analytics и Яндекс Метрики.

Как проанализировать данные с помощью R:

Шаг 1. Устанавливаем инструменты

Язык программирования R
RStudio — среда для разработки, для запуска скриптов и дальнейшей визуализации

Шаг 2. Прописываем код

— Прописываем путь к рабочей папке

setwd("C:/Users/dmitry_moskvin/sendsay.ru/predict_issue_time")  

— Загружаем необходимые для работы библиотеки

if(!require(data.table)){  
  install.packages("data.table")
  library(data.table)
}

if(!require(lubridate)){  
  install.packages("lubridate")
  library(lubridate)
}

— Загружаем данные для работы

stat_uni <- fread("file.csv") # название вашего файла с данными

names(stat_uni) <- c("member.id",  
                     "issue.id",
                     "issue.dt",
                     "read.dt",
                     "click.dt")

stat_uni[stat_uni == ""] <- NA  

— Отбираем рассылки, в которых участвовали более 10% подписчиков

huge_issues <- stat_uni[, .N, by = issue.id][  
  N >=length(unique(stat_uni$member.id)) * 0.1,1]

stat_uni <- stat_uni[issue.id %in% huge_issues$issue.id,]  

— Переводим столбцы с датами в нужный формат

stat_uni$issue.dt <- parse_date_time(stat_uni$issue.dt,  
                                     orders = '%Y-%m-%d %H:%M:%S')

stat_uni$read.dt <- parse_date_time(stat_uni$read.dt,  
                                    orders = '%Y-%m-%d %H:%M:%S')

stat_uni$click.dt <- parse_date_time(stat_uni$click.dt,  
                                     orders = '%Y-%m-%d %H:%M:%S')

— Прорабатываем время по рассылкам

stat_uni$issue_wday <- weekdays.POSIXt(stat_uni$issue.dt,  
                                          abbreviate = F)
stat_uni$issue_time <- hour(stat_uni$issue.dt)  

— Прорабатываем время по открытиям

stat_uni$read_wday <- weekdays.POSIXt(stat_uni$read.dt,  
                                         abbreviate = F)
stat_uni$read_time <- hour(stat_uni$read.dt)  
stat_uni$read_dur <- as.numeric(stat_uni$read.dt -  
                                  stat_uni$issue.dt,
                                units = "mins")

— Прорабатываем время по кликам

stat_uni$click_time <- hour(stat_uni$click.dt)  
stat_uni$click_dur <- as.numeric(stat_uni$click.dt -  
                                   stat_uni$issue.dt,
                                 units = "mins")

— Убираем столбцы с датами

stat_uni <- stat_uni[,-c(3, 4, 5)]  

— Собираем агрегированную статистику

all_stats <- stat_uni[, .(count_issues = length(unique(issue.id)),  
                                 count_members = length(member.id),
                                 open_rate = round(mean(!is.na(read_time)),digits = 4),
                                 open_count = sum(!is.na(read_time)),
                                 open_median = round(median(read_dur,na.rm = T),0),
                                 click_rate = round(mean(!is.na(click_dur)),digits = 4),
                                 click_count = sum(!is.na(click_dur)),
                                 click_median = round(median(click_dur,na.rm = T),0)),
                             by = c("issue_wday", "issue_time")]

— Считаем веса рассылок и подписчиков в этих рассылках

all_stats$issues_prop <- round(sapply(all_stats$count_issues,  
                                                function(x) x/sum(all_stats$count_issues)),
                                         digits = 4)

all_stats$members_prop <- round(sapply(all_stats$count_members,  
                                                 function(x) x/sum(all_stats$count_members)),
                                          digits = 4)

— Считаем коэффициенты дня недели и часа рассылки

coef_time <- stat_uni[,.(open_rate_time = round(mean(!is.na(read_time)),digits = 4),  
                            click_rate_time = round(mean(!is.na(click_time)),digits = 4)),
                         by = issue_time][, .(issue_time, time_success = 0.3*open_rate_time + 0.7*click_rate_time)]

coef_wday <- stat_uni[,.(open_rate_wday = round(mean(!is.na(read_time)),digits = 4),  
                            click_rate_wday = round(mean(!is.na(click_time)),digits = 4)),
                            by = issue_wday][, .(issue_wday, day_success = 0.3*open_rate_wday + 0.7*click_rate_wday)]

— Объединяем данные из таблицы агрегированной статистики

all_stats <- merge(all_stats,  
                   coef_time,
                   all.x = T,
                   by = 'issue_time')

all_stats <- merge(all_stats,  
                   coef_wday,
                   all.x = T,
                   by = 'issue_wday')

— Рассчитываем итоговые результаты по открытиям и кликам с учетом всех весов и коэффициентов

all_stats$open_results <- rank(-(all_stats$open_rate *  
  all_stats$issues_prop *
  all_stats$members_prop *
  all_stats$time_success *
  all_stats$day_success))
  all_stats$click_results <-  rank(-(all_stats$click_rate * 
  all_stats$issues_prop *
  all_stats$members_prop *
  all_stats$time_success *
  all_stats$day_success))

— Убираем вспомогательные столбцы

all_stats <- all_stats[,c(1:5,7,8,10,15,16)]  

— Приводим итоговую таблицу в читабельный вид

all_stats <- all_stats[,.("Время рассылки" = paste(issue_wday, issue_time, sep = ":"),  
             "Количество выпусков" = count_issues,
             "Количество участников" = count_members,
             "Open rate" = paste0(round(open_rate*100,2)," %"),
             "Click rate" = paste0(round(click_rate*100,2)," %"),
             "Время перед открытием" = open_median,
             "Время перед кликом" = click_median,
             "Результат по открытиям" = open_results,
             "Результат по кликам" = click_results)]

— Сохраняем в csv

write.csv(x = all_stats,  
          file = "stats.csv",
          na = "",
          row.names = F,fileEncoding = "UTF-8")

Если у вас небольшая база и вы только начинаете анализировать данные — следуйте общим, проверенным правилам, параллельно экспериментируя и изучая своих подписчиков. При работе с крупной базой и частыми рассылками — пользуйтесь нашим алгоритмом. И не забывайте, что правильно подобранное время для рассылки важно, но не первостепенно. Во главе угла — персонализация и качественный контент.

SENDSAY
Мультиканальная маркетинговая платформа