Статьи по программированию

Простой скрипт email рассылки

26 августа 2019  

Постановка задачи и выбор методов её решения

Задача: написать максимально быстро и просто скрипт для отправки e-mail сообщения на n-ное количество адресов. Дело в том, что иногда нужно послать письмо нескольким адресатам, но так, чтобы они друг о друге не знали. То есть, исключаем тупое копирование всех адресов через запятую в поле «Кому».

Приступим.

Почему PHP? Да потому что на PHP это сделать очень просто и он стоит на любом хостинге (платном конечно). Тем более, скрипт не нужно хранить на компьютере, а лучше залить на сервер и пользоваться откуда угодно. Даже с мобильника.

Если говорить более простым языком, мы пишем небольшой скрипт e-mail рассылки. Сразу же в голове рождается представление работы скрипта.

У нас есть форма с полями:

Кому (список получателей)

Тема сообщения

Текст сообщения

Адрес отправителя (выбор из перечня)

Схема работы: Вводим данные и нажимаем «Отправить» → происходит отправка писем → получаем отчёт.

Есть также пару особенностей. Для отправки писем желательно использовать небольшой тайм-аут, чтобы наш сервер не посчитали спаммером. Отчёт желательно записать в небольшой текстовый файл. Нужно защитить скрипт от несанкционированного использования.

Пишем скрипт

Здесь я не буду описывать процесс написания, а просто приведу максимально откомментированный код.

 

<?php
  // Устанавливает лимит времени исполнения для этого файла (связано с тайм-аутом)
 set_time_limit (1200);
  // Адреса отправителя
 $mail1="ваше имя 1 <your1@email.com>";
 $mail1="ваше имя 2 <your2@email.com>";
 $mail1="ваше имя 3 <your3@email.com>";

  // Обрабатываем адреса для отображения в форме
 $tmail1=htmlspecialchars($mail1);
 $tmail2=htmlspecialchars($mail2);
 $tmail3=htmlspecialchars($mail3);
 
  // далее идет сам скрипт
  // Если массив POST не пустой, отправка состоялась
 if (!empty($_POST) && !isset($sent)) {
 
// Определяем переменные
 $emailer_subj = $_POST['emailer_subj'];
 $emailer_mails = $_POST['emailer_mails'];
 $emailer_text = $_POST['emailer_text'];
 $emailer_yourmail = $_POST['emailer_yourmail'];

 // Теперь проверяем заполнение всех полей
 if (empty($emailer_subj) || $emailer_subj=="Тема письма") {
 // Если тема пустая...
 $mail_msg='<b>вы не ввели тему письма</b>';
  } elseif (empty($emailer_mails) || $emailer_mails=="Почтовые адрсе") {
 // Если адресов нет...
 $mail_msg='<b>Не указано адреса получателей</b>';
  } elseif (empty($emailer_text) || $emailer_text=="Текст письма") {
 // Если сообщение пустое...
 $mail_msg='<bы не ввели текст письма</b>';
  } else { // Если все поля заполнены верно...
 // готовим сообщение об успешной отправке... вдруг у вас какой-то необычный браузер
 $mail_msg=аше сообщение отправлено.<br>Нажмите <a href="'.$_SERVER['REQUEST_URI'].'">здесь</a>, если ваш браузер не поддерживает перенаправление.';
 // готовим заголовки письма... будем отправлять письма в формате HTML и кодировке UTF-8
 $headers="MIME-Version: 1.0\r\n";
 $headers.="Content-type: text/html; charset=utf-8\r\n";
 $headers.="From: $emailer_yourmail";
 
 // Обработка письма. Нужно удалить лишние пробелы и проставить переносы.
 $emailer_text=preg_replace("/ +/"," ",$emailer_text); // множественные пробелы заменяются на одинарные
 $emailer_text=preg_replace("/(\r\n){3,}/","\r\n\r\n",$emailer_text); // убираем лишние переносы (больше 1 строки)
 $emailer_text=str_replace("\r\n","<br>",$emailer_text); // ставим переносы
 
 // Получаем массив адресов. в качестве разделителя у нас используется запятая.
 $emails=explode(",", $emailer_mails);
 $count_emails = count($emails); // Подсчет количества адресов
 // запускаем цикл отправки сообщений
 for ($i=0; $i<=$count_emails-1; $i++) // Отчет начинается в массиве с нуля, поэтому уменьшаем сумму на единицу
 {
 // Подставляем адреса получаетелей и обрезаем пробелы с обоих сторон, если таковые имеются
 $email=trim($emails[$i]);
 // Отправляем письмо и готовим отчет по отправке
 if($emails[$i]!="") { // Проверка на случай попадения в массив пустого значения
 if(mail($email,$emailer_subj,$emailer_text,$headers)) $report.="<li><span style=\"color:green;\">Отправлено: ".$emails[$i]."</span></li>"; else $report.="<li><span style=\"color:red;\">Не отправлено: ".$emails[$i]."<span></li>";
 sleep(5); // делаем тайм-аут в 5 секунд
 }
 }
 
 //  Файл будет сгенерирован в той же папке, под названием log.txt. Проверьте настройку прав папки.
 $log=fopen("log.txt","w");
 fwrite($log,$report);
 fclose($log);
 // Переменная $sent признак успешной отправки
 $sent=1;
  }
} else { // Если в массиве POST пусто, форма еще не передавалась
  // готовим приглашение
  $mail_msg='поля обязательны для заполнения.';
  // Поля темы, адресов получаетелей и получателей, и текста в этом случае должны быть пустыми
  $emailer_text=$emailer_subj=$emailer_mails=$emailer_yourmail='';
}

  // Если $sent не существует, выводим форму или отчет
 if (!isset($sent)) {
  // Если сообщение уже отправлено - выводим отчет
 if(isset($_GET['messent']))
 {echo $text.="<b style=\"text-align:center;margin-top:200px;display:block;\">все окей. Сообщение отправлено. <a href=\"emailer.php\">Еще'?</a><br><br><u>Отчет:</u></b> <ol style=\"display:block;width:300px;margin:10px auto;\">";
 readfile("log.txt");
 echo"</ol>";}
 else {
  // если выводим форму, если сообщение еще' не отправлено
 echo $text.=<<<post
 <script type="text/javascript">
 function form_validator(form) {
 if (form.emailer_subj.value=='' || form.emailer_subj.value=='Тема письма') { alert('Укажите тему письма.'); form.emailer_subj.focus(); return false; }
 if (form.emailer_mails.value=='' || form.emailer_mails.value=='Почтовые адреса') { alert('Укажите адреса получаталей.'); form.emailer_mails.focus(); return false; }
 if (form.emailer_text.value=='' || form.emailer_text.value=='Текст письма') { alert('вы не заполнили поле сообщения.'); form.emailer_text.focus(); return false; }
 return true;
 }
 </script>
 <style type="text/css">
 form {display:block;margin:20px auto;width:500px;}
 textarea, input, select {width:100%; margin:5px 0;}
 textarea {height:200px;}
 .red {color:#a00;}
 </style>
 <form method="post" onsubmit="return form_validator(this);">
 <p class="red">$mail_msg</p>
 <input type="text" name="emailer_subj" id="emailer_subj" value="Тема письма" title="По какому поводу пишем?" onfocus="if (this.value=='Тема письма') this.value='';" onblur="if (this.value=='') this.value='Тема письма';">
 <textarea name="emailer_mails" id="emailer_mails" title="Кто получатели?" onfocus="if (this.value=='Почтовые адреса') this.value='';" onblur="if (this.value=='') this.value='Почтовые адреса';">Почтовые адреса</textarea>
 <textarea name="emailer_text" id="emailer_text" title="Что пишем?" onfocus="if (this.value=='Текст письма') this.value='';" onblur="if (this.value=='') this.value='Текст письма';">Текст письма</textarea>
 <select name="emailer_yourmail">
 <option value="$mail1">$tmail1</option>
 <option value="$mail2">$tmail2</option>
 <option value="$mail3">$tmail3</option>
 </select>
 <input type="submit" value="Отправить" title="Отправить мыл">
 </form>
post;
}
}
else { // А если существует...
  // Посылаем в заголовке редирект (303 Refresh) на этот же адрес с дополнительным параметром messent
  $ret_uri=$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
  header("Refresh: 0; URL=http://".$ret_uri."?messent");
  exit;
}

?>

Защита скрипта

Создайте папку, где будет находиться скрипт, и положите туда файл .htaccess, с таким содержанием. Эти пару строк ограничат доступ по IP адресу.

 

<?php
Order Deny,Allow
Deny from all
Allow from ваш IP
?>

Или, если у вас не постоянный IP адрес, можно добавить пароль.

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// посылаем браузеру запрос логина/пароля
header("WWW-Authenticate: Basic realm=\"Enter login and password\"");
header("HTTP/1.0 401 Unauthorized");
exit;
} else {
if($_SERVER['PHP_AUTH_USER']!==аш логин' && $_SERVER['PHP_AUTH_PW']!=='ваш пароль')
{
header("WWW-Authenticate: Basic realm=\"Enter login and password\"");
header("HTTP/1.0 401 Unauthorized");
exit(веден неверный логин или пароль');
}
else {
//Сюда нужно вставить тело скрипта
}
?>

Доработка скрипта

Конечно, можно бесконечно дорабатывать этот скрипт, ведь решение написано «на коленке», однако свою функцию он выполняет. Неоднократно пользовался им и сбоев не было.

Например, можно задавать список адресов получателей из текстового файла (можно прямо выбирать адреса из текста). Или сделать отправку с помощью перезапуска работы скрипта (чтобы не было проблем с функцией set_time_limit () на любом хостинге). Или писать подробные отчёты и отсылать их на ваше e-mail.

Можно вставить себя последним в списке, чтобы проконтролировать отправку. Вдруг что с файлом случится :)

Надеюсь, эта статья поможет вам в освоении языка программирования PHP.