Sendmail-заглушка для PHP и на PHP

image

Каждый раз настраивая локальный вебсервер, сталкиваюсь с вопросом о заглушке для Sendmail.

Есть прекрасное решение для Windows: fake sendmail for windows (sendmail.exe) http://glob.com.au/sendmail/
На хабре есть статья об этом решении: PHP mail под Windows http://habrahabr.ru/post/26518/
Ещё одно решение под Windows: Test Mail Server Tool http://www.toolheap.com/test-mail-server-tool/
Так же есть статья для линуксоидов: Sendmail-заглушка для Linux http://habrahabr.ru/post/49665/

Лично мне больше понравилось решение на чистом PHP, о котором и пойдёт дальнейшее описание.


Особенность этого решения в том, что для его настройка минимальна, можно даже обойтись без самого файла, если конечно вам нет нужды знать содержимое сообщения. На мой взгляд, такой метод стоит того, что бы о нём знали другие разработчики PHP.

Вопрос в том, что является вашим приоритетом как разработчика, ваши потребности от заглушки, а также ваш уровень знаний и умений.

Из плюсов:
  • Отсутствие сторонних сервисов
  • Кроссплатформенное решение для OS на которой установлен PHP
  • Минимальный размер файла заглушки
  • Минимальная настройка
  • Вся логика заглушки доступна для редактирования на PHP
  • Сохранение сообщения в файле


Из минусов:
  • Отсутствие пересылки на реальный почтовый ящик
  • Отсутствие удобного доступа к отправленным сообщениям


Список аргументов и возможностей заглушки:
  • --dir <Путь к папке> — Папка для файлов
  • --file <имя файла> — Сохранять каждое сообщение в конкретном общем файле
  • --prepend — Добавлять новое сообщение в начало общего файла
  • --open — Автоматически открывать файл сообщения в Notepad


Параметры для PHP.INI файла:

[mail function]
;SMTP = localhost
;smtp_port = 25
;sendmail_from = me@example.com
sendmail_path = "php.exe C:\sendmail.php --dir C:\mail --open"


Если путь к php.exe прописан в PATH, то можно не указывать его в PHP.INI иначе желательно изменить php.exe на <Путь к папке с PHP>\php.exe

sendmail_path = "C:\server\bin\php\php.exe C:\sendmail.php --dir C:\mail --open"


На линукс можно сразу указать путь к файлу, не забыв предварительно сделать его запускаемым: chmod 755 sendmail.php
sendmail_path = "/home/someuser/sendmail.php --dir /tmp/mail"


Сам sendmail.php скрипт:

#!/usr/bin/env php

<?php
/*  PHP.INI
*  [mail function]
*  ;SMTP = localhost
*  ;smtp_port = 25
*  ;sendmail_from = me@example.com
*  sendmail_path = php.exe sendmail.php --dir C:\mail --open
*/

$is_windows = stristr(PHP_OS, 'WIN');
$options = getopt("", ['open', 'prepend', 'file:', 'dir:']);
$is_open = isset($options['open']);
$is_prepend = isset($options['prepend']);
$is_onefile = isset($options['file']);
$mail_dir = isset($options['dir']) ? $options['dir'] : sys_get_temp_dir().'/mail';
$file_name = isset($options['file']) ? $options['file'] : mkname();
$file_path = $mail_dir.'/'.$file_name;

if( !is_dir( $mail_dir ) ) {
  mkdir( $mail_dir, 0777, TRUE );
  if( !is_dir( $mail_dir ) ) {
    die('Mail folder ['.$mail_dir.'] not created');
  }
}

$stream = $is_onefile ? PHP_EOL . str_repeat("-=", 10) . date('Y-m-d H:i:s') . str_repeat("-=", 10) . PHP_EOL : '';
while (false !== ($line = fgets(STDIN))) {
  $stream .= ($is_windows ? str_replace("\n", PHP_EOL, $line) : $line);
}

if($is_prepend && file_exists($file_path)) {
  $file_contents = file_get_contents($file_path);
  $stream .= $file_contents;
}

file_put_contents($file_path, $stream, $is_prepend ? 0 : FILE_APPEND);

if ($is_open && $is_windows){
  pclose(popen("start /B notepad ". $file_path, "r"));
}

function mkname($i=0) {
  global $mail_dir;
  $fn = 'mail_'.date('Y-m-d_H-i-s_').$i.'.txt';
  return file_exists($mail_dir.'/'.$fn) ? mkname(++$i) : $fn;
}


Как я и обещал, есть также возможность обойтись совсем без файла.

sendmail_path = "C:\server\bin\php\php.exe -r 'echo 1;'"


Либо использовать упрощённый вариант решения

sendmail_path = "C:\server\bin\php\php.exe C:\sendmail.php"


sendmail.php:

#!/usr/bin/env php

<?php
$mail = '';
while (false !== ($line = fgets(STDIN))) {
  $mail .= $line;
}
file_put_contents("c:/mail/mail.txt", $mail . PHP_EOL . str_repeat("-=", 20) . PHP_EOL, FILE_APPEND);


Буду рад, если Вам это будет полезным.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 21

    +2
    mailtrap, имхо
      +1
      Попробуйте mailcatcher
        0
        Который тянет за собой кучу зависимостей.
        +2
        Решений на чистом PHP достаточно много (например smtp catcher), выше привели пример гема mailcatcher. Вопрос насколько все это целесообразно в виде поста?
          +2
          Вопрос в том, что является приоритетом для разработчика, а также его уровень знаний и умений.
          Данное решение отлично от других, тем что оно минимально по своему размеру, легко расширяется, платформо-независимо и не требует дополнительной настройки. Конечно же у него есть и свои минусы, такие как отсутствие удобного доступа к полученным сообщениям. Но именно это и не является главным требованием к заглушке.
          На мой взгляд, такой метод стоит того, что бы о нём знали другие разработчики PHP.
          +2
          На линуксах использовал ssmtp с привязкой к «Яндекс почте для домена», все устраивало.
            +1
            Уж простите за глупый вопрос, но: А почему бы просто сразу не использовать swiftmailer? Он, помимо прочего, умеет в dummymailer со всеми вытекающими возможностями для тестирования и отлова сообщений.
              0
              Вопрос в потребностях. Это решение идеально подходит там, где важно что бы скрипт продолжил работу, а значение сообщения минимально. Например: сообщения об ошибках дублируемых по почте.
              Там где важно само сообщение, и его форматирование, конкретное решение не подходит.
                +1
                swiftmailer умеет собирать абсолютно все данные о сообщении (в том числе содержание, тему, всех получателей, заголовки, форматирование), а вы можете их сохранить в любом удобном для вас формате.
                  0
                  На мой взгляд, главный недостаток, что там где используется PHP mail функция, это работать не будет. А заменить на Swift Mailer возможно не во всех ситуациях, например чужой проект в котором требуется добавить модуль. В любом случае, спасибо за комментарий, думаю что сама тема отправки писем из PHP и сравнение всех решений и библиотек, должна быть интересна для PHP разработчиков.
              0
              И кстати, чем вас не устроила константа PHP_OS? (Не успел отредактировать)
                0
                Поправил, спасибо.
                0
                Почему при локальной разработке просто не использовать какой-нибудь обычный email аккаунт (например, gmail) для отправки сообщений?
                Зачем искать сложности, и потом их преодолевать?
                  0
                  Мне кажется, что fake sendmail заглушки имеют несколько достоинств в отличие от внешнего SMTP сервера:
                  1. Независимо от интернет подключения.
                  2. Все отправленные сообщения будут задержаны, вне зависимости от адреса получателя.
                  Думаю что есть и другие достоинства, которые я не учёл.
                  –2
                  Еще решение
                  python -m smtpd -n -c DebuggingServer localhost:25
                  
                    0
                    Да на Gmail SMTP настраиваем и всё. Не нужно никаких заглушек. Вот пример для GNU/Linux: wiki.archlinux.org/index.php/SSMTP. Вот пример для Symfony2: symfony.com/doc/current/cookbook/email/gmail.html.
                      0
                      Я оставлю это здесь: getopt
                        0
                        Поправил, спасибо.
                        0
                        Вначале не заметил, но:

                        лучше использовать константу STDIN;
                        обязательно заменить "#!/usr/local/bin/php" на "#!/usr/bin/env php" (у большинства, ИМХО, php лежит в "/usr/bin", а у некоторых даже в "/opt".
                          0
                          Поправил, спасибо за Ваши комментарии.
                          0
                          Пользуюсь похожим решением. Хочу добавить, что если сохранять письмо с расширением .eml, то его можно открывать почтовыми клиентами, например Mozilla Thunderbird. В таком случае вполне адекватно видно форматирование письма, в том числе можно отлаживать HTML верстку и видеть аттачи.
                          Чтобы метод работал, каждое письмо должно сохраняться в отдельном файле.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое