@Heyhihello

Как разрешить ошибку mail(): Multiple or malformed newlines found in additional_header?

Здравствуйте!

Столкнулся с ошибкой, которую не могу разрешить уже 3ий день. Еще в июне эта форма работала как часики и отправляла файлы на имейл без никаких нареканий. Теперь вот такая ошибка вылетает:

mail(): Multiple or malformed newlines found in additional_header'

Соб-но, код:

$eol = PHP_EOL;
 $boundary = md5(time());

        $user_name = $_POST['contact_user_name'];
        $user_email = trim($_POST['contact_user_email']);

        $subject = "Новая заявка на лечение с сайта MAYDOOK GROUP";
        $headers = "From: " . $user_name;
        $headers .= "<" . $user_email . ">" . $eol;
        $headers .= "Reply-To:" . trim($_POST['contact_user_email']) . $eol;
        $headers .= "MIME-Version: 1.0" . $eol;

        $message = "" . "Данные о контактном лице:  <br> Имя: " . trim($_POST['contact_user_name']) . "<br>Адрес электронной почты (E-mail): " . trim($_POST['contact_user_email']) . "<br> Номер телефона: " . trim($_POST['contact_user_phone']) . "<br><br>Данные о пациенте: <br> ФИО Пациента: " . $_POST['patient_user_name'] . "<br>Желаемое время приезда: " . $_POST['patient_date_arrive'] . "<br> Наличие визы: " . $shengen . "<br><br>Цель обращения (отмеченные пункты): " . "<br>" . $check_1 . "<br>" . $check_2 . "<br>" . $check_3 . "<br>" . $check_4 . "<br>" . $check_5 . "<br>" . $check_6 . "<br>" . $check_7 . "<br>" . $check_8;

        $message .= "<br><br> Сообщение:<br><br>" . stripslashes(trim($_POST['user_message']));

        if (isset($_FILES['file']['name'])) {
            $file_name = $_FILES['file']['name'];
            $temp_name = $_FILES['file']['tmp_name'];
            $file_type = $_FILES['file']['type'];

            $base = basename($file_name);
            $extension = substr($base, strlen($base) - 4, strlen($base));

            $allowed_extensions = array(".doc", ".docx", ".pdf", ".png", ".jpg", ".rar", ".zip");


            if (in_array($extension, $allowed_extensions)) {

                $file = $temp_name;
                $content = chunk_split(base64_encode(file_get_contents($file)));

                $headers .= "Content-Type: multipart/mixed; boundary=\"" . $boundary . "\"" . $eol . $eol;
                $headers .= "Content-Transfer-Encoding: 7bit" . $eol;
                $headers .= "This is a MIME encoded message." . $eol . $eol;

                //текстовое сообщение
                $headers .= "--" . $boundary . $eol;
                $headers .= "Content-Type: text/plain; charset=\"iso-8859-1\"" . $eol;
                $headers .= "Content-Transfer-Encoding: 8bit" . $eol . $eol;
                $headers .= $message . $eol . $eol;


                //наш аттачмент
                $headers .= "--" . $boundary . $eol;
                $headers .= "Content-Type: " . $file_type . "; name=\"" . $file_name . "\"" . $eol;
                $headers .= "Content-Transfer-Encoding: base64\n";
                $headers .= "Content-Disposition: attachment; filename=\"" . $file_name . "-\"" . $eol . $eol;
                $headers .= $content . $eol . $eol;
                $headers .= "--" . $boundary . "--";

            } else {
            }
        }


        error_reporting(E_ALL ^ E_NOTICE);
        if (mail("buferrodinvv19@gmail.com", $subject, "", $headers)) {
            $status = "Сообщение успешно отправлено...<br>";
        } else {
            $status = "Error!.<br>";

            $err = error_get_last();
            var_export($err);
        }


Буду премного благодарен людям, которые помогут и объяснят, в чем может быть проблема. Искал в интернете, и нашел всего пару тем, в которых рассматривают данный трабл.

И еще нашел вот это: https://bugs.php.net/bug.php?id=68776 - но тут ничерта неясно и нет никаких руководств по исправлению
  • Вопрос задан
  • 6826 просмотров
Решения вопроса 1
@Heyhihello Автор вопроса
xtreme: Получается, только в одном месте нужно оставить два $eol подряд? Вот так?

// Email header
                $header = "From: " . $user_name . " <" . trim($_POST['contact_user_email']) . ">" . PHP_EOL;
                $header .= "Reply-To: " . trim($_POST['contact_user_email']) . PHP_EOL;
                $header .= "MIME-Version: 1.0" . PHP_EOL;


                $header .= "Content-Type: multipart/mixed; boundary=\"" . $boundary . "\"" . PHP_EOL;
                $header .= "This is a multi-part message in MIME format." . PHP_EOL;
                $header .= "--" . $boundary . PHP_EOL . PHP_EOL;

                // Email content
                // Content-type can be text/plain or text/html
                $header .= "Content-type:text/plain; charset=iso-8859-1" . PHP_EOL;
                $header .= "Content-Transfer-Encoding: 7bit" . PHP_EOL;
                $header .= "$message" . PHP_EOL;
                $header .= "--" . $boundary . PHP_EOL;

                // Attachment
                $header .= "Content-Type: application/xml; name=\"" . $file_name . "\"" . PHP_EOL;
                $header .= "Content-Transfer-Encoding: base64" . PHP_EOL;
                $header .= "Content-Disposition: attachment; filename=\"" . $file_name . "\"" . PHP_EOL;
                $header .= $content . PHP_EOL;
                $header .= "--" . $boundary . "--";


Я добавил еще такую вот функцию и обернул $headers при отправке в нее:

function validateMail($str) {
    return str_replace(array('\r\r', '\r\0', '\r\n\r\n', '\n\n', '\n\0', PHP_EOL . PHP_EOL), '', $str);
}


Теперь вместо ошибки просто отображается NULL и сообщение не отправляется. (UPD. Стоял лимит от хостинга в 20 сообщений на внешние ящики. А сам код работал нормально.)

UPD. Ответ на 2ой комментарий.

Честно сказать, вот те письма, что отправлялись без проблем. Как видно тут больше пустых строк и почему-то отправлялось. Опять же, очень странно, что один и тот же код работал какое-то время, а потом резко перестал. :)
f7a889e31b134d0e9eb26b9a2b9f99f2.png

UPD. Решение проблемы:

Лучше всего использоваться PHP_EOL вместо \n или \r\n - сама определяется в зависимости от ОС
И разделить headers

$header = "From: " . $from . $endl;
               $header .= "Reply-To: " . $user_email . $endl;
                $header .= "MIME-Version: 1.0" . $endl;

                $header .= "Content-Type: multipart/mixed; boundary=\"" . $uid . "\"" . $endl . $endl;
                $emessage = "--" . $uid . "\n";
                $emessage .= "Content-type:text/html; charset=utf-8\n";
                $emessage .= "Content-Transfer-Encoding: 7bit\n\n";
                $emessage .= $message . "\n\n";

                $emessage .= "--" . $uid . "\n";
                $emessage .= "Content-Type: application/octet-stream; name=\"" . $file_name . "\"\n";
                $emessage .= "Content-Transfer-Encoding: base64\n";
                $emessage .= "Content-Disposition: attachment; filename=\"" . $file_name . "\"\n\n";
                $emessage .= $content . "\n\n";

                $emessage .= "--" . $uid . "--";


Отправлять так:
mail($to, $subject, $emessage, $header);

У меня проблема была в этом и в том, что на хостинге лимит в 20 сообщений на внешние ящики стоит. :) Капец злой был.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
Jakim
@Jakim
Laravel - developer
<?php
/**
 * Created by PhpStorm.
 * User: Jakim
 * Date: 08.11.2017
 * Time: 3:37
 */
$EOL = "\r\n"; // ограничитель строк, некоторые почтовые сервера требуют \n - подобрать опытным путём
$boundary     = "--".md5(uniqid(time()));  // любая строка, которой не будет ниже в потоке данных.
$subject_text = 'Тест от меня';
$subject= '=?utf-8?B?' . base64_encode($subject_text) . '?=';
$message = 'текст сообщения';
$headers    = "MIME-Version: 1.0;" . $EOL . "";
$headers   .= "Content-Type: multipart/mixed; boundary=\"" . $boundary . "\"" . $EOL . "";
$headers   .= "From: jakimoff1990@gmail.com\nReply-To: jakimoff1990@gmail.com\n";

$multipart  = "--" . $boundary . $EOL;
$multipart .= "Content-Type: text/html; charset=utf-8" . $EOL . "";
$multipart .= "Content-Transfer-Encoding: base64" . $EOL . "";
$multipart .= $EOL; // раздел между заголовками и телом html-части
$multipart .= chunk_split(base64_encode($message));

#начало вставки файлов

foreach($_FILES["file"]["name"] as $key => $value){
    $filename = $_FILES["file"]["tmp_name"][$key];
    $file = fopen($filename, "rb");
    $data = fread($file,  filesize( $filename ) );
    fclose($file);
    $NameFile = $_FILES["file"]["name"][$key]; // в этой переменной надо сформировать имя файла (без всякого пути);
    $File = $data;
    $multipart .=  "" . $EOL . "--" . $boundary . $EOL . "";
    $multipart .= "Content-Type: application/octet-stream; name=\"" . $NameFile . "\"" . $EOL . "";
    $multipart .= "Content-Transfer-Encoding: base64" . $EOL . "";
    $multipart .= "Content-Disposition: attachment; filename=\"" . $NameFile . "\"" . $EOL . "";
    $multipart .= $EOL; // раздел между заголовками и телом прикрепленного файла
    $multipart .= chunk_split(base64_encode($File));

}

#>>конец вставки файлов

$multipart .= "" . $EOL . "--" . $boundary . "--" . $EOL . "";

if(!mail('jakimoff1990@gmail.com', $subject, $multipart, $headers)){
    echo 'Письмо не отправлено';
} //Отправляем письмо
else{
    echo 'Письмо отправлено';
}

Там немного поменялись у людей заголовки, сам заморочился пока собрал все в кучу.
Ответ написан
@xtreme
Снимаю порчу по SSH :)
Я не PHP-программист, но принимал участие в борьбе с данной фичей. Багом назвать язык не поворачивается, поскольку это сообщение - последствия исправления бага в PHP, позволяющего отправлять неправильные письма.
Если проштудировать diff исходников самого PHP того самого фикса - картина следующая:
При формировании заголовков в письме, перенос строки должен выглядеть либо как \r\n либо как \n.
Если между \r и \n есть какой-либо символ (там ловится \0), либо перепутан порядок символов, либо если встречается два \n\n подряд - формируется сообщение
Multiple or malformed newlines found in additional_header

Два символа \n подряд могут встретиться в заголовках, если встречается рядом два переноса строк. Допустим, заканчивается одна строка и после нее стоит еще одна пустая строка, состоящая только из переноса - получаем ошибку.

Когда привели в порядок все заголовки - пало подозрение, что PHP ругается на разделение между заголовками и телом письма (там тоже пустая строка). В конце концов получилось обойти данную фичу тем, что кодировали само тело письма в base64 и выставляли Content-Transfer-Encoding: base64
PHP ругаться перестал, письма стали отправляться, исправление костылей отложили "на потом".
Ответ написан
@NickHander
mail(): Multiple or malformed newlines found in additional_header'

Для устранения этой ошибки необходимо исключить двойной перенос строки (\n\n) или аналогично двойной eol в переменной записи хедеров. Можно все заголовки с двойным переносом перенести в body (emassage), а в header оставить только заголовки без двойных переносов. Результат будет прежним, зато ошибки не будет, и все будет работать как часики=)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы