Рассылка пользователям сайта с выборкой адресов с рядом условий 1.X

280
Потребовалось разослать информационное сообщение зарегистрированным пользователям сайта.
Обычно я не делаю рассылок, поэтому для этого случая у меня нет какого то постоянного решения, компонента, плагина.
Сервис email рассылок отверг сразу - ради одного раза не хотелось заморачиваться, платить, ждать модерации своего письма, да и сливать базу адресов своих пользователей на сторонний сервис лишний раз тоже не хотелось бы.

Немного поискал готовые скрипты, ничего интересного не нашёл и появилось такое решение.

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


1. Создаю текстовый файт sitenews.txt с содержимым примерно таким

Код PHP:
  1. [subject:Обновления на сайте]
  2.  
  3. Здравствуйте!
  4.  
  5. Здесь какой то текст письма.
  6.  
  7. В качестве примера форматирования письма можно посмотреть как устроен текстовый файл /languages/ru/letters/newcomment.txt и поменяв там текст, сохранить в новый текстовый файл
  8.  
  9. ---------
  10.  
  11. С уважением, администрация сайта сайт.ру
  12.  
загружаю этот файл sitenews.txt в папку /languages/ru/letters

2. В базе данных в таблицу cms_users добавляю столбец `emailsent`

Здесь я буду отмечать факт отправки письма в рамках рассылки этому пользователю. Изначально по умолчанию значение ячейки 0, после отправки письма этому пользователю оно будет меняться на 1. При осуществлении рассылки скрипт будет брать только те адреса, в которых статус всё ещё 0.

SQL запрос в myphp

Код PHP:
  1. ALTER TABLE `cms_users` ADD `emailsent` INT(1) NOT NULL DEFAULT '0' AFTER `openid`;

3. Создаю файл sitenews.php

Этот файл кидаю в папку /includes/myphp/

Содержимое файла:

Код PHP:
  1. <?php
  2.  
  3. //подключаем базу и файл с содержимым письма
  4. $inDB = cmsDatabase::getInstance();
  5. $letter = cmsCore::getLanguageTextFile('sitenews');
  6.  
  7.  
  8. //комментарии к запросу далее в посте
  9. $sql = "SELECT u.email, u.id
  10. FROM cms_users u
  11. LEFT JOIN cms_user_profiles p ON p.user_id = u.id
  12. WHERE u.is_deleted = 0 AND u.is_locked = 0 and u.emailsent = 0
  13. AND u.email NOT LIKE '%yandex.ru%' AND u.email NOT LIKE '%gmail.com%' AND (u.group_id = 1 OR u.group_id = 10) AND p.email_newmsg = 1
  14. LIMIT 1";
  15.  
  16. $result = $inDB->query($sql);
  17. while ($item = $inDB->fetch_assoc($result)){
  18.  
  19. //отправляем письмо методами системы.
  20. cmsCore::mailText($item['email'], '', $letter);
  21. //проставляем отметку об отправке письма этому пользователю
  22. $inDB->query("UPDATE cms_users SET emailsent = 1 WHERE id = '{$item['id']}'");
  23.  
  24. echo $item['email'];
  25. echo 'ok';
  26.  
  27. }
  28.  
  29. //подсчитаем сколько писем отправлено и сколько осталось. Запрос такой же как первый, но здесь не будем устанавливать лимит.
  30.  
  31. $sql = "SELECT u.email, u.id
  32. FROM cms_users u
  33. LEFT JOIN cms_user_profiles p ON p.user_id = u.id
  34. WHERE u.is_deleted = 0 AND u.is_locked = 0 and u.emailsent = 0
  35. AND u.email NOT LIKE '%yandex.ru%' AND u.email NOT LIKE '%gmail.com%' AND (u.group_id = 1 OR u.group_id = 10) AND p.email_newmsg = 1";
  36.  
  37.  
  38. $result = $inDB->query($sql);
  39. $all_users = $inDB->num_rows($result);
  40. $total_sent = $inDB->rows_count('cms_users', "emailsent = 1");
  41.  
  42.  
  43. echo 'всего отправлено: '.$total_sent;
  44. echo 'осталось: '.$all_users;
  45.  
  46.  
  47.  
  48. //cmsCore::mailText('[email protected]', '', $letter);
  49. //выше тестовая отправка на свой адрес. Чтобы использовать, раскомментировать строку и указать свой адрес.
  50.  
  51. //header("Refresh: 2;");
  52. //автообновление страницы с подключенным скриптом для автозапуска скрипта каждый 2 секунд, если лень жать F5
  53.  
  54. ?>
Ниже комментарии к основному SQL запросу, для тех, кто не понял, они помогут настроить запрос под свои обстоятельства. Я использовал ряд условий.

1. Рассылать будем только тем кто не удалён и не заблокирован
Код PHP:
  1. WHERE u.is_deleted = 0 AND u.is_locked = 0
2. а так же тем, кому ещё не отправляли
Код PHP:
  1. and u.emailsent = 0
3. Пользователям, в адресах которых содержится определённый домен рассылать не будем. Скорее всего, вам это не нужно, можете удалить это условие в двух запросах. Мне это было нужно, поэтому у меня так.

Код PHP:
  1. AND u.email NOT LIKE '%yandex.ru%' AND u.email NOT LIKE '%gmail.com%'
4. Рассылаем только пользователям из группы 1 (пользователи) и группы 10 (своя группа).

Код PHP:
  1. AND (u.group_id = 1 OR u.group_id = 10)
4. И ещё одно условие.
Я рассылаю только тем пользователям, который в настройках своего профиля НЕ запретили уведомления о личных сообщениях и комментариях с сайта на свой email

Код PHP:
  1. AND p.email_newmsg = 1

5. Ну и лимит за один проход. Я отправлял по одному письму.
Код PHP:
  1. LIMIT 1";

4. Через админку сайта создаю страницу с любым названием и адресом.


В настройках страницы указываем, что эта страница доступна только админу. В тело страницы через опцию "внешний файл" вставляют наш скрипт
Код PHP:
  1. {ФАЙЛ=sitenews.php}
Теперь, чтобы отправить первое письмо, просто откройте эту страницу в браузере. Чтобы повторить нажмите F5. Можно поставив автозапуск, раскомментировать последнюю строку в коде или поставить на cron. Но в случае с CRON, очевидно, придётся открыть доступ к странице. В таком случае можно использовать GET параметр с секретным ключём, чтобы избежать несанкционированного запуска скрипта, здесь описывать это не буду.

Дальше текст не имеет отношения к инструкции, просто заметки на тему

Я знал, что у меня на хостинге имеется лимит в 1500 исходящих email в сутки. Запустил скрипт на автообновление страницы еще и в двух вкладках браузера сразу. И когда уже было отправлено 850 писем (быстро) обнаружил, что на хостинге так же имеется лимит в 150 писем в час...

Пришлось остановиться и ждать около часа пока обновится лимит. Потом продолжил пачками по 100 - 120 писем в час.

Как я понимаю, из первой партии 850 писем отправлены и доставлены были только первые 150. Остальные 700 отправлены не были из-за ограничения хостинга, но мой скрипт проставил в базе данных отметку (1), что письма отправлены.

Теперь, чтобы всё же отправить письма тем, кого я упустил, думаю сделать вот что...

После обхода всей базы в базе данных сброшу значение столбца emailsent на 0 для всех пользователей.

Код PHP:
  1. UPDATE `cms_users` SET `emailsent`= 0;
в коде закомментирую строку

Код PHP:
  1. // cmsCore::mailText($item['email'], '', $letter);
, чтобы при запуске скрипта письмо не отправлялось.

Запущу скрипт на автообновлении, после прохода 150 строк с пользователям, раскомментирую закомментированную часть кода и продолжу отправку писем, пока общий счетчик отправленных писем не приблизится опять к 850, но теперь с учётом часового лимита на хостинге.
Аватары пользователей в ленте активности | Подход к организации мультиязычности на сайте с выносом на поддомен но без дублирования файлов
Комментарии (1)
Нил™ 6 июля 2020 в 23:14 0
bbcode редактор Instanta режет здесь тег br точнее заменяет его в тексте (внутри тега code) на перенос строки.