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

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

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

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


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

  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

  1. ALTER TABLE `cms_users` ADD `emailsent` INT(1) NOT NULL DEFAULT '0' AFTER `openid`;

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

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

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

  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('myadress@gmail.com', '', $letter);
  49. //выше тестовая отправка на свой адрес. Чтобы использовать, раскомментировать строку и указать свой адрес.
  50.  
  51. //header("Refresh: 2;");
  52. //автообновление страницы с подключенным скриптом для автозапуска скрипта каждый 2 секунд, если лень жать F5
  53.  
  54. ?>
Ниже комментарии к основному SQL запросу, для тех, кто не понял, они помогут настроить запрос под свои обстоятельства. Я использовал ряд условий.

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

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

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

  1. AND p.email_newmsg = 1

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

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


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

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

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

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

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

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

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

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

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

Запущу скрипт на автообновлении, после прохода 150 строк с пользователям, раскомментирую закомментированную часть кода и продолжу отправку писем, пока общий счетчик отправленных писем не приблизится опять к 850, но теперь с учётом часового лимита на хостинге.
0
Нил™ Нил™ 4 года назад #
bbcode редактор Instanta режет здесь тег br точнее заменяет его в тексте (внутри тега code) на перенос строки.

Еще от автора

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