Первые шаги
Пользовательские данные
- Обзор адаптивного email-редактора
- Создание оформления для письма
- Создание сквозных модулей
- Настройка адаптивности
- Настройка smart-контейнеров
- Оформление промовкладки для Gmail
- Добавление Ролловера
- Добавление анкорных ссылок
- Библиотека модулей
- Добавление таблицы в письмо
- Работа с блоком "Баннер"
- Добавление пользовательских шрифтов
- Создание кнопки CTA
- Работа с блоком "Картинка"
- Работа с блоком “Таймер"
- Использование ИИ в email-редакторе
- Поддержка мессенджер-протоколов почтовыми клиентами и платформами
Омниканальность
- SDK для мобильных приложений
- Управление ключами доступа к мобильному SDK
- Подключение мобильного приложения
- Создание и загрузка ключа Firebase
- Создание мобильных push-сообщений
- Настройка аналитики доставляемости и кликов
- Планирование мобильных push-уведомлений
- Типы диплинков
- Отправка тестовых сообщений из отладки запросов
- Настройка виджетов для сайта
- Геймификация виджетов
- Вызов виджета
- Настройка геоданных для правил вызова виджетов
- Сохранение данных из виджетов в поля контактов
- Защита от раздражения
- Действия после заполнения формы
- Замена системного сценария Double Opt-In
- Создание pop-up-форм с помощью Google Tag Manager или WordPress
- Отправка событий из форм подписки в Google Analytics
- A/B-тестирование виджетов
- Сбор контактных данных с помощью форм запросов
Автоматизация
- Настройка и редактирование сценариев
- Настройка условий запуска и остановки сценария
- Блок “Старт”
- Группа блоков “Популярные”
- Группа блоков “Сообщения”
- Использование блока сообщений "Одно из многих"
- Группа блоков “Контакт”
- Группа блоков "Условия"
- Группа блоков “Другое”
- Группа блоков “Сообщение на группу”
- Группа блоков “Время”
- Расширенные параметры блоков сценариев
- Разрешенное время отправки
- Вебхуки в сценариях
- Отслеживание истории запусков сценария
- Если сценарий не работает
- Двойное подтверждение подписки
- Приветственная серия
- Приветственная серия с сегментацией по категориям
- Запуск сценария после импорта контактов
- Регулярный сценарий для группы
- Поздравление с днем рождения
- Привязка сценария к кнопке
- Использование переменных из заказа в сценарии
- Сбор отзывов о заказе
- Реактивация клиентов и подписчиков
- Отправка рассылки непрочитавшим
- Настройка дополнительных рассылок
- Отправка напоминаний в заданное пользователем время
- А/B-тестирование в сценариях
Персонализация
- Подстановка промокода из файла
- Подстановка промокода с использованием API
- Принципы генерации промокодов с помощью PHP/JAVA
- Подстановка промокода с помощью персонализации
- Загрузка промокодов для использования в сценарии
- Генерация промокодов в сценарии
- Отправка промокода с помощью препроцессора
- HTTP-запрос для передачи промокода из сообщения в карточку контакта
Аналитика
- Отчёт по email-рассылке
- Отчет по SMS-рассылке
- Отчет по рассылке Web Push
- Отчет по Viber-рассылке
- Отчет по рассылке Mob Push
- Отчет по рассылке App Inbox
- Отчет по Telegram-рассылке
- Отчет по взаимодействию с In-App
- Отчет по взаимодействию с виджетами
- Отчет по триггерной рассылке
- Отчет по AMP-рассылке
- Отчет по мультиязычной рассылке
- Настройка передачи UTM-меток
- Визуализация дохода
- Отслеживание эффективности кампаний в Google Analytics 4
- Статистика сообщений
Мультиязычность
Отслеживание событий и поведения
- События для запуска триггерных рассылок
- Именование пользовательских событий
- Валидация параметров события
- Отслеживание активности на сайте при помощи Generate event
- Подстановка данных из событий в сообщения
- Разветвление сценария в зависимости от параметров события
- Отслеживание активности клиентов в мобильных приложениях
- Вебхуки для отслеживания активности
- Аналитика событий
Товарные рекомендации
API
Смена системы
Документы
Интеграция
Принципы генерации промокодов с помощью PHP/JAVA
Если общие методы подстановки промокодов вам не подходят, рассмотрите возможность реализации этой задачи с помощью PHP/JAVA.
Формат промокода, который поддерживает eSputnik
Промокод содержит дату, до которой он действует, тип акции, размер скидки и контрольную сумму.
В результате получим такую строку:
<YY><MM><DD><Promo type><Discount><CRC>
Поле Длина Описание Пример YY 2 символа Год, двузначное число 15, 54 MM 2 символа Месяц, двузначное число, если надо, дополняется слева нулем 01, 12 DD 2 символа День, двузначное число, если надо, дополняется слева нулем 06, 28 Promo type 1 символ Тип промокода, может принимать значение от 0 до 31, кодируется символом из алфавита Base32 A, D, X Discount 2 символа Размер скидки в %, двузначное число, если надо, дополняется нулем слева 15, 02 CRC 1 символ Контрольная сумма – одно из значений алфавита Base32 B, N, Z В результате получается строка длиной 10 символов такого вида: 151231Y16N
Обратите внимание
Значение промокодов зависит от параметров блока и текущего календарного числа. То есть в течение суток все контакты будут получать одинаковый промокод, если в параметры блока не будут вноситься изменения. Отслеживание использования промокода и срока его действия должно происходить на вашей стороне.
Пример использования типа промокода (Promo type)
- 0 – действует для всей корзины (must-have)
- 1 – действует только для категории А
- 2 – действует только для категории В
Важно!
Если вы хотите использовать типы промокода таким образом, отправьте файл в поддержку eSputnik, указав, какая категория продукта соответствует тому или иному коду.
Алгоритм расчета контрольной суммы (CRC)
- По порядку суммируется десятичное ASCII-значение каждого символа в исходной строке.
- Полученная сумма делится с остатком на 32.
- Полученный остаток используется как индекс символа в алфавите Base32.
Символ по этому индексу и будет контрольной суммой.
Пример кода на Java:
public static final String BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; public char checkSum(String data) { int sum = 0; for (char c : data.toCharArray()) { sum += c; } return BASE32_ALPHABET.charAt(sum % BASE32_ALPHABET.length()); }
Кодирование/декодирование промокода
Для кодирования/декодирования используется симметричный алгоритм шифрования Triple DES.
Чтобы получить человекочитаемый текст, полученные с помощью шифрования данные кодируются с помощью Base32.
Используемые параметры шифрования:
- ключ длиной 24 байта
- initialisation_vector длиной 8 байт
- режим шифрования: CFB8 (Cipher Feedback Mode)
- дополнение: NoPadding
Последовательность действий при кодировании промокода
- К промокоду применяется алгоритм шифрования Triple DES.
- Чтобы получить человекочитаемый текст, полученные с помощью шифрования данные кодируются с помощью Base32.
- Через каждые 4 символа для читабельности добавляется “-”.
Последовательность действий при декодировании промокода
- Удалите “-”.
- Сначала данные декодируются при помощи Base32.
- Далее декодированные данные расшифровываются при помощи Triple DES.
- Должна получиться строка из 10 символов согласно описанному выше формату. Для контроля правильности расшифровки используется контрольная сумма.
Секретный ключ
Для кодирования и декодирования промокодов секретный ключ используется на стороне eSputnik и на стороне сервиса, который проверяет промокоды.
Сгенерируйте ключ eSSuperKeyXXXXXXXXXXXXXX (где ХХХ… – случайные цифры) и создайте вектор инициализации: 12345678.
Важно
Вектор инициализации всегда должен быть 12345678.
Передайте оба эти значения в поддержку eSputnik.
Пример Java-кода
package promocode; import java.security.spec.KeySpec; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.codec.binary.Base32; public class CryptData { private KeySpec keySpec; private SecretKey key; private IvParameterSpec iv; public CryptData(String keyString, String ivString) { try { keySpec = new DESedeKeySpec(keyString.getBytes("UTF-8")); key = SecretKeyFactory.getInstance("DESede") .generateSecret(keySpec); iv = new IvParameterSpec(ivString.getBytes("UTF-8")); } catch (Exception e) { e.printStackTrace(); } } public String encrypt(String value) { try { Cipher ecipher = Cipher.getInstance("DESede/CFB8/NoPadding"); // "SunJCE"); ecipher.init(Cipher.ENCRYPT_MODE, key, iv); if (value == null) return null; // Encode the string into bytes using utf-8 byte[] valeur = value.getBytes("UTF-8"); // Encrypt byte[] enc = ecipher.doFinal(valeur); // Encode bytes to base64 to get a string String encodedString = new String(new Base32().encode(enc), "UTF-8"); StringBuilder sb = new StringBuilder(); for (int i = 0 ; i < encodedString.length(); ++i) { if (0 != i && i % 4 == 0) { sb.append("-"); } sb.append(encodedString.charAt(i)); } return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { String encrypt = new CryptData("eSSuperKeyXXXXXXXXXXXXXX", "12345678").encrypt("770101K99N"); System.err.println(encrypt); } }
Пример PHP-кода
<?php class Base32 { /** * Table for encoding base32 * * @var array */ private static $encode = array( 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 2, 27 => 3, 28 => 4, 29 => 5, 30 => 6, 31 => 7, 32 => '=', ); /** * Table for decoding base32 * * @var array */ private static $decode = array( 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 2 => 26, 3 => 27, 4 => 28, 5 => 29, 6 => 30, 7 => 31, '=' => 32, ); /** * Creates an array from a binary string into a given chunk size * * @param string $binaryString String to chunk * @param integer $bits Number of bits per chunk * @return array */ private static function chunk($binaryString, $bits) { $binaryString = chunk_split($binaryString, $bits, ' '); if (substr($binaryString, (strlen($binaryString)) - 1) == ' ') { $binaryString = substr($binaryString, 0, strlen($binaryString)-1); } return explode(' ', $binaryString); } /** * Encodes into base32 * * @param string $string Clear text string * @return string Base32 encoded string */ public static function encode($string) { if (strlen($string) == 0) { // Gives an empty string return ''; } // Convert string to binary $binaryString = ''; foreach (str_split($string) as $s) { // Return each character as an 8-bit binary string $s = decbin(ord($s)); $binaryString .= str_pad($s, 8, 0, STR_PAD_LEFT); } // Break into 5-bit chunks, then break that into an array $binaryArray = self::chunk($binaryString, 5); // Pad array to be divisible by 8 while (count($binaryArray) % 8 !== 0) { $binaryArray[] = null; } $base32String = ''; // Encode in base32 foreach ($binaryArray as $bin) { $char = 32; if (!is_null($bin)) { // Pad the binary strings $bin = str_pad($bin, 5, 0, STR_PAD_RIGHT); $char = bindec($bin); } // Base32 character $base32String .= self::$encode[$char]; } return $base32String; } /** * Decodes base32 * * @param string $base32String Base32 encoded string * @return string Clear text string */ public static function decode($base32String) { if (strlen($base32String) == 0) { // Gives an empty string return ''; } // Only work in upper cases $base32String = strtoupper($base32String); // Remove anything that is not base32 alphabet $pattern = '/[^A-Z2-7]/'; $base32String = preg_replace($pattern, '', $base32String); $base32Array = str_split($base32String); $string = ''; foreach ($base32Array as $str) { $char = self::$decode[$str]; // Ignore the padding character if ($char !== 32) { $char = decbin($char); $string .= str_pad($char, 5, 0, STR_PAD_LEFT); } } while (strlen($string) %8 !== 0) { $string = substr($string, 0, strlen($string)-1); } $binaryArray = self::chunk($string, 8); $realString = ''; foreach ($binaryArray as $bin) { // Pad each value to 8 bits $bin = str_pad($bin, 8, 0, STR_PAD_RIGHT); // Convert binary strings to ASCII $realString .= chr(bindec($bin)); } return $realString; } } $base32 = new Base32; $key = "eSSuperKey10050012345678"; $iv = "12345678"; $encoded = "ILDD-2V7W-SBWD-2X34"; echo "DECODED: " . mcrypt_decrypt(MCRYPT_3DES, $key, str_replace("-", "", $base32::decode($encoded)), MCRYPT_MODE_CFB, $iv) . "\n"; ?>
Важно!
Используйте Format Preserving Encryption, чтобы упростить перевод кода в человекочитаемый вид.