Sendmail-заглушка для Linux

    Не так давно встала задача, установить заглушку для sendmail, дабы письма из PHP не отсылались на ложные адреса (при тестинге) или просто не возникала ошибка, а складывались аккуратно в папку. Аналогично тому, как это делает Денвер.
    Далее…

    Поиск по просторам интернета ничего не дал, кроме советов читать мануал к sendmail. Но терпение и упорство сделали свое дело. И, спустя несколько дней, на одном из форумов нахожу интересный шелл-скрипт.
    Мне пришлось немного поправить его, для своих нужд. Итак, тело скрипта:

    #!/bin/sh
    prefix="/var/mail/sendmail/new"
    numPath="/var/mail/sendmail"

    if [ ! -f $numPath/num ]; then
    echo "0" > $numPath/num
    fi
    num=`cat $numPath/num`
    num=$(($num + 1))
    echo $num > $numPath/num

    name="$prefix/letter_$num.txt"
    while read line
    do
    echo $line >> $name
    done
    chmod 777 $name
    /bin/true

    Скрипт сохраняем в папку /usr/bin под любым угодным вам именем и делаем исполняемым (sudo chmod +x). Я использовал fake_sendmail.sh.

    Теперь все исходящие письма будут складываться в /var/mail/sendmail. Так же необходимо выставить для папки права на запись. (chmod 777 -R /var/mail/sendmail).

    Примечание:
    Для сбора писем почтовиком (о чем ниже), нужно в этой папке создать следующую структуру папок:
    /var/mail/sendmail/
    — cur
    — new
    — tmp
    И дать права на запись.

    Настройка PHP.
    У меня стоит Кубунта, так что все пути относительно нее. Итак, находим в папке /etc/php5/apache2 файл php.ini и меняем в нем путь к sendmail на:

    sendmail_path = /usr/bin/fake_sendmail.sh.

    Все, на этом можно и закончить. Далее читать страждущим юзабилити.

    Привязка локальной папки к KMail.
    Запускаем KMail и переходим в опции создания нового аккаунта:
    Settings -> Configure KMail -> Accounts -> Add.

    Выбираем maildir mailbox, а в настройках этого аккаунта, собственно, путь к папке с письмами (/var/mail/sendmail).
    Все, закончено. Теперь эти письма можно будет забирать почтовиком и читать в удобоваримом виде.
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 36
    • +1
      полезно, спасибо(:
      • 0
        а не пробовали просто менять адресата на username@localhost?
        • +2
          а если по условиям задачи нужно потестить как рз генерацию адресатов?
          • –1
            письмо — это набор заголовков и текста, который идет после них. если вы замените заголовок «To:» на локальный адрес, а дополнительно создадите еще один заголовок, например «XXX-To:», куда запишете тестируемое поле, то вы решите вашу задачу. и вместо копания в гугле и терминале, вы просто добавите пару строк кода.
            • 0
              На вкус и цвет, как говорится…
              Лично мне проще один раз прикрутить скрипт и пользоваться чем каждый раз добавлять/убирать 2 строчки кода. Возможно Вы считаете по другому, но, повторюсь, кому как удобнее.
        • +1
          Здорово, что кто то додумался написать то, что мне самому писать было лень :) Спасибо огромное!
          • 0
            спасибо, мне просто так удобнее отлаживать письма для разных адресатов, да еще читаемо в почтовом клиенте!
            • +3
              Если мне не изменяет память, то для сендмайла достаточно написать в /etc/mail/mailertable

              . local:username

              где username — ваш логин. И тогда всю вашу почту сендмайл будет складывать в ваш почтовый ящик на вашей же машине.
              • 0
                Чтобы никто больше не мучился, вот неплохая инструкция по этому поводу:
                Сделайте бэкап sendmail.mc и sendmail.cf.

                Сначала проверьте, что /etc/mail/sendmail.mc содержит строку:

                FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl

                Если её там нет — добавьте (у меня например не было).

                Скомпилируйте изменения конфига (мне лично тут потребовалось колдовство с chmod & chown):

                $ m4 /etc/mail/sendmail.mc>/etc/mail/sendmail.cf

                Добавьте изменения в /etc/mail/mailertable.
                (строка. local:username)

                Сгенерируйте базу mailertable.db:
                $ makemap hash /etc/mail/mailertable </etc/mail/mailertable

                Перезапустите sendmail.

                $ service sendmail restart

              • 0
                А для postfix достаточно добавить в /etc/postfix/main.cf строку «default_transport = error»
                • +2
                  А не проще fakemail воспользоваться???
                  • 0
                    Она требует ставить либо Перл либо Питон (под виндой к примеру). а если уже есть cygwin — не проще ли просто прикрутить скриптик, чем возиться с указанными языками.
                  • +2
                    Хотелось бы в общих чертах понять, зачем ставить 777 на текстовые файлы?
                    • +4
                      Это эмуляция обычной работы под админом в Windows :)
                      • 0
                        chmod -R 777 любимая команда молодых пхп программистов, которым нравится Ubuntu
                        • 0
                          руки бы поотрывал за такое (:
                      • 0
                        Предлагаю тоже неплохой вариант, пишется общий лог, и в папке mail для каждого адреса создается свой лог (написано на sh.exe из cygwin):

                        maildir="/d/www/mail"
                        mainlog="/d/www/mail.log"
                        tmpfile="/d/www/mail.tmp"

                        function cleanup()
                        {
                        rm -f "$tmpfile"
                        exit 1
                        }

                        trap cleanup ERR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

                        # Имя файла с логом (определяется из заголовка To:)
                        filename="_unknown"

                        # Красивый заголовок
                        echo "-----------------------" >> "$mainlog"
                        echo "-----------------------" >> "$tmpfile"

                        while read line
                        do
                        [[ "${line#To: }" != "$line" ]] && filename="${line#To: }"
                        echo "$line" >> "$mainlog"
                        echo "$line" >> "$tmpfile"
                        done

                        echo >> "$mainlog"
                        echo >> "$mainlog"

                        echo >> "$tmpfile"
                        echo >> "$tmpfile"

                        mv "$tmpfile" "$maildir/$filename.log"

                        Для подключения скрипта под Win пишем что-то вроде:

                        sendmail_path = sh.exe /d/web-server/sendmail.sh

                        в php.ini
                        • –1
                          Поправьте, пожалуйста, теги. Картину в профиле внимания портят. ;)
                          • 0
                            Метки через запятую перечисляться должны. Зачем минусовать? Хотя, как хотите. :)
                          • +1
                            Самый простой вариант:
                            #!/bin/sh
                            /usr/lib/python2.5/smtpd.py -n -c DebuggingServer localhost:25

                            и все письма выводятся в консоль
                            • 0
                              Большое спасибо. Только-только встал вопрос о настройке sendmail в Убунте, а тут ваша статья, очень кстати.
                              • 0
                                Вы, наверное, что-то не совсем поняли. Тут нет никакого сендмейла :)
                                • 0
                                  Мне именно это и нужно было. Тестирование на локальном сервере отправки почты для тестирования системы уведомлений :)
                                  Теперь меня интересуют вопросы: какой почтовый сервер выбрать, как его установить/настроить и прикрутить к пхп?
                                  • +1
                                    Если где-то в сети уже есть почтовик, то попробуйте nullmailer. Он просто перебрасывает почту на smarthost.
                            • 0
                              спасибо, я исправлю. это мой первый пост.
                              • 0
                                Сегодня попросили реализовать такое и кинули ссылку на этот топик :)
                                Скрипт упростил. Чтобы не запоминать номер в файле используется date с наносекундами. Ну и права конечно же.

                                #!/bin/sh
                                prefix="/mnt/php_mail"
                                date=`date \+\%Y\%m\%d\%H\%M\%N`

                                name="$prefix/$date.eml"
                                while read line
                                do
                                echo $line >> $name
                                done
                                chmod 666 $name

                                • 0
                                  у меня почему-то наносекунды не выводятся, просто N показует и все, хотя остальное — ок
                                  • 0
                                    Поправочка: нужно использовать IFS, а также $line должен быть в кавычках, иначе обрезаются пробелы по краям, что критично для заголовков писем. Они могут либо вообще не открываться в почтовых программах, либо быть обрезанными
                                    #!/bin/sh
                                    prefix="/var/www/sendmail"
                                    date=`date \+\%Y\%m\%d\%H\%M\%N`
                                    
                                    name="$prefix/$date.eml"
                                    while IFS= read line
                                    do
                                    echo "$line" >> $name
                                    done
                                    chmod 666 $name
                                    
                                  • 0
                                    Огромное спасибо за статью!
                                    • 0
                                      В Evolution (у меня Ubuntu 10.10) в параметрах «Тип сервера» нужно выбрать «Почтовые каталоги в формате Maildir»
                                      • 0
                                        Автору — спасибо!

                                        На случай, если в этот топик в поисках забежит ещё один джангист кроме меня:
                                        В django, начиная с версии 1.2, все извращения с sendmail остались позади.
                                        Существуют различные email-backends, в том числе file-backend

                                        Чтобы искалось: Django Sendmail Development Plug
                                        • 0
                                          единственная проблема с этим скриптом — при отправке из PHP формы сообщений сразу нескольким адресатам или при отправки копии письма себе (что одно и то же), этот скрипт все ложит в один файл, каким образом отслеживать конец сообщения и начинать писать в новый файл?
                                          • 0
                                            может кому-то пригодится, набрел на статью, описывающую скрипт-заглушку, написанный на самом php
                                            www.drupal.ru/node/31183

                                            Для себя немного переписал и на freebsd завелось нормально
                                            в php.ini
                                            sendmail_path = "/usr/local/bin/php /localetc/sendmail_stub/fake.php"

                                            и сам fake.php

                                            $sendMailStubObj = new SendMailStub();
                                            $sendMailStubObj->main();
                                            
                                            class SendMailStub
                                            {
                                                private $_saveEmailsPath = "/mnt/windev/tmp/__sendmail/"; //change path HERE
                                            
                                                function main()
                                                {
                                                    //--- get email from the stream ---//
                                                    $stream_data = '';
                                                    $stream_handler = fopen('php://stdin', 'r');
                                                    while ($t = fread($stream_handler, 2048)) {
                                                        if ($t === chr(0))
                                                            break;
                                                        $stream_data .= $t;
                                                    }
                                                    fclose($stream_handler);
                                            
                                                    //save to file
                                                    $fwrite_handler = fopen($this->_generateUniquePath(), 'w');
                                                    fwrite($fwrite_handler, $stream_data);
                                                    fclose($fwrite_handler);
                                                }
                                            
                                                private function _generateUniquePath()
                                                {
                                                    $i = 0;
                                                    do {
                                                        $path = $this->_saveEmailsPath . $this->_generateFname($i);
                                                        $i++;
                                            
                                                        if($i > 100){
                                                            break;
                                                        }
                                                    } while (file_exists($path) == true);
                                            
                                                    return $path;
                                                }
                                            
                                                private function _generateFname($i = 0)
                                                {
                                                    $parts = array(
                                                        date('Y-m-d_H-i-s'),
                                                    );
                                            
                                                    if ($i > 0) {
                                                        $parts[] = "_{$i}";
                                                    }
                                                    $parts[] = ".eml";
                                            
                                                    $fname = implode("", $parts);
                                            
                                                    return $fname;
                                                }
                                            }
                                            
                                            • 0
                                              Будьте аккуратны с использованием этого варианта.

                                              while read line
                                              do 
                                                  echo $line >> $name 
                                              done 
                                              

                                              будет интерпретировать текст письма как баш скрипт и, например, * заменит на список файлов в текущей директории.

                                              Правильный вариант
                                              while read line
                                              do 
                                                  echo "$line" >> $name 
                                              done
                                              
                                              • 0
                                                Есть чудесная заглушка прямо в php.ini:

                                                sendmail_path = /bin/cat > "/tmp/mail_`date +%Y-%m-%d_%H-%M-%S`"


                                                Нужно только убедиться в наличии /bin/cat и прав на запись в /tmp/

                                                P.S. велосипед не мой

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