Добро пожаловать! Это — архивная версия форумов на «Хакер.Ru». Она работает в режиме read-only.
 

Функция mail: продвинутый анализ

Пользователи, просматривающие топик: none

Зашли как: Guest
Все форумы >> [Веб-программинг] >> Функция mail: продвинутый анализ
Имя
Сообщение << Старые топики   Новые топики >>
Функция mail: продвинутый анализ - 2011-03-23 02:40:48.110000   
Agent Smith

Сообщений: 976
Оценки: 0
Присоединился: 2007-04-10 21:56:49.593333
Если вы используете поиск по форуму, то вы найдете старую статью Орба о mail() PHP - http://forum.xakep.ru/m_1369038/tm.htm
Мне не совсем нравится, как он пишет (не по феншую), потому я написал свою статью на эту тему, где постарался более широко раскрыть тему. Саму статью можно найти здесь http://www.hevyweb.com.ua/programming/php/73-functionmailphp.html, но что бы меня не обвинили в спаме, я скопирую статью ниже. У меня просьба к людям, которые разбираются в PHP, а лучше в MIME, напишите ваше мнение. Может, я что-то не правильно написал в статье, очень рад буду услышать (прочитать) конструктивную критику.

—————————-линия отрыва—————————————-

В данной статье я продемонстрирую, как работает функция mail языка программирования PHP. Эта статья будет полезна как начинающему программистам, так и более опытным. В ней я постараюсь навести примеры работы с функцией mail без использования соответственных классов PEAR.
В первую очередь хочу обратить внимание, что на некоторых бесплатны хостингах апач собран без поддержки этой функции, или она отключена в php.ini, или существуют ограничения по данной функции. Это делается с целью ограничить попытки рассылки спама, потому, прежде всего, проверьте свой сервер.

Несколько слов о самой функции.
Если вы обратитесь к мануалам http://ru.php.net/manual/en/function.mail.php вы сможете прочитать, что функция mail имеет 5 параметров
mail ( string $to , string $subject , string $message, string $additional_headers, string $additional_parameters)
- $to – электронный адрес получателя почты.
- $subject – тема письма.
- $message – текст письма.
- $additional_headers – (необязательный параметр) – дополнительные заголовки письма. На этом более детально я остановлюсь немного пожже.
- $additional_parameters - (необязательный параметр) – дополнительные параметры письма. К сожалению, ни в официальном мануале, ни на сайте W3C, ни на хабре я не нащел всего списка, а также точного значения всех ключей, которые используются в этом параметре, потому не буду блуждать в потемках.
После выполнения функция mail() вернет вам TRUE или FALSE в зависимости от того, отправлено ли письмо успешно или нет.

Самый простой пример отправки почты
Рассмотрим наипростейший пример. Допустим, нужно оправить письмо с темой «Привет мир» на адрес test@test.ru. Так как письмо у нас на русском, то для корректного отображения, нужно использовать кодировку UTF-8.
$subject="Привет мир";
$subject= mb_encode_mimeheader($subject,"UTF-8", "B", "\n");
Здесь мы подготавливаем заголовок к отправке. Большинство почтовых служб и клиентских программ правильно распознают кодировку письма и соответственно заголовка, но некоторые – нет, на пример mail.ру.
Можно также использовать следующую конструкцию для заголовка:
Хочу обратить ваше внимание, что если тема письма и файл, в котором находится ваш код, уже находятся в кодировке UTF-8, то такие действия приведу к искажению темы, потому нужно проверить это при помощи функции mb_detect_encoding.
Но так как у нас пример простейший, пока не будем обращать внимания на кодировку.

<?php
$subject="Привет мир";
$message="Текст письма";
$to = "test@test.ru";

If (mail ($to, $subject, $message))
{
Echo "Письмо удачно отправлено";
}
Else
{
Echo "Сбой при отправлении письма";
}
?>
Если у вас все прошло гладко в первом примере, то на почтовый адрес test@test.ru должно было прийти письмо с обратным адресом, который является дефолтным для текущего почтового сервера. Также хочу заметить, что функция mb_encode_mimeheader относится к семейству "Мультибитных" и поддерживается лишь начиная с версии PHP 4.0.6. Однако на некоторых хостингах, а также в денвере все это "семейство функций" может не работать, так как библиотека php_mbstring.dll на Денвере обычно отключена. Для такого, что бы её включить нужно раскомментировать её в вашем php.ini (убрать символ ";" перед extension=php_mbstring.dll) и проверить само наличие этой библиотеки.

Более сложный пример отправки почты.
И так рассмотрим более сложный пример. Задача, которая стоит перед нами:
Отослать на электронный адрес test@test.ru письмо с обратным адресом отправителя hevyweb@test.ru, а также сделать копию на адрес copy@test.ru и copy1@test.ru, а также сделать скрытую копию на адрес hidden_copy@test.ru
В этом случае нам нужно использовать четвертый параметр функции mail. Я не буду рассказывать о переменных, о котором речь шла в первом примере, а перейду сразу к четвертому. Он состоит из строк, каждая из которых разделена символом переноса строки. Каждая строка состоит из Ключа и его значения. Название ключа стоит перед двоеточием, значение – после.

$headers[] ="MIME-Version: 1.0";
Указываем версию MIME стандарта, который обеспечивает передачу различных типов данных по электронной почте. Обычно это 1.0, по крайней мере, других версий я пока не встречал,
$headers[] ="Content-Type: text/plain; charset=utf-8";
Указываем, что формат нашего письма – обычный текст, а кодировка UTF-8.
$headers[] ="From: ".$from;
Указываем имейл, который является обратным адресом. Здесь параметр $from может иметь 2 вида и оба они правильны:
1) $from="hevyweb@test.ru";
2) $from = '=?UTF-8?B?'.base64_encode("Василий Пупкин").'?='. "<hevyweb@test.ru>";
Что бы не исказилось имя отправителя от того, что бы используем русские буквы, нужно соответственным образом закодировать его. Теперь получателю придет письмо от Василия Пупкина, но и адрес получателя будет видет.
Обратите внимание, что в первом случае, указан просто адрес отправителя, а во втором – адрес отправителя в треугольных скобках. Если вы ошибетесь с форматом отправителя, то получателю в графе отправитель будет отображаться либо "неизвестный отправитель", либо дефолтный адрес вашего почтового сервера.
$headers[] ="Reply-To: ".$from;
$headers[] ="Return-Path: ".$from;
Reply-To и Return-Path – ключи одинакового значения. Я не нашел сведений, в которых было бы написано в чем разница между ними, однако я нашел информацию о том, что некоторые почтовые клиенты используют только Return-Path, а другие – только Reply-To. Оба эти параметра указывают адрес, по которому должен ответить получатель письма. Он может отличаться от адреса From. В случае, если этот параметр не указан, его дефолтным значением будет значение параметра с ключом From.
$headers[] ="X-Mailer: PHP/" . phpversion();
Имейл клиент или библиотека, в которой было создано письмо. Обычно пишут версию PHP под которой работает текущий скрипт, в котором находится функция mail(), однако не запрещено вместо этого написать какой-то дургой текст, на пример test.ru или MyMailer Script.

$headers[] ="CC: ".$copy;
Адрес(а), куда нужно отослать копию письма. Все члены рассылки будут видеть других абонентов. В переменной $copy можно указать несколько адресом через запятую использую конструкцию приведенную выше.
$copy = '=?UTF-8?B?'.base64_encode("Иванов Иван").'?='." <copy@test.ru>, ".'=?UTF-8?B?'.base64_encode("Петров Петр").'?='." <copy1@test.ru>";
$headers[] ="BCC: ".$hiddencopy;
Ключ BCC будет включать в себя перечень всех емейл адресов, которым нужно отправить скрытую копию письма, о которой не должен знать ни главный получатель, них другие оппоненты. В нем нету смысла использовать имена получателей ("Получатель <hidden_copy@test.ru>"), потому можно просто перечислить адреса через запятую.
$headers[] ="BCC: hidden_copy@test.ru";

$headers[]= "X-Priority: 1 (Higuest)";
$headers[]= "X-MSMail-Priority: High";
$headers[]= "Importance: High";
Некоторые почтовые клиенты поддерживают такой параметр, как уровень приоритетности, который можно использовать для придания письму важности.
Теперь все эти кусочки нужно собрать воедино.
Каждая строка в заголовке должна отделяться от предыдущей символом переноса строки. В зависимости от того, на каком сервер у вас стоит ваш срипт, перенос строки будет либо "\r\n" для линукса, либо "\n" для Виндовса. Однако в виндовсе можно использовать также "\r\n". Разница между ними в том, что "\n" – просто переносит курсом на новую строку, а "\r\n" – возвращает на её начало. Потому будет использовать "\r\n".
$header=implode("\r\n", $headers);
Функция implode склеивает все части массива $headers строку при помощи разделителя "\r\n". Можно писать все вручную в одну строчку, но мне кажется, что так проще. И так вот наши пример.

<?php
$subject="Привет мир";
if (mb_detect_encoding($subject, "UTF-8")==FALSE)
$subject= mb_encode_mimeheader($subject,"UTF-8", "B", "\n");

$message="Текст письма";
$to = "test@test.ru";

$headers[] ="MIME-Version: 1.0";
$headers[] ="Content-Type: text/plain; charset=utf-8";
$from ='=?UTF-8?B?'.base64_encode("Василий Пупкин").'?='. "<hevyweb@test.ru>";
$headers[] ="From: ".$from;
$headers[] ="Reply-To: ".$from;
$headers[] ="Return-Path: ".$from;
$headers[] ="X-Mailer: PHP/" . phpversion();
$copy = '=?UTF-8?B?'.base64_encode("Иванов Иван").'?='." <copy@test.ru>, ".'=?UTF-8?B?'.base64_encode("Петров Петр").'?='." <copy1@test.ru>";
$headers[] ="CC: ".$copy;
$headers[] ="BCC: hidden_copy@test.ru";
$headers[]= "X-Priority: 1 (Higuest)";
$headers[]= "X-MSMail-Priority: High";
$headers[]= "Importance: High";
$header=implode("\r\n", $headers);

If (mail ($to, $subject, $message, $header))
{
Echo "Письмо удачно отправлено";
}
Else
{
Echo "Сбой при отправлении письма";
}
?>

Отправка простого письма в HTML формате с вложением.
Здесь я покажу на примере, как отправить не сложный HTML текст на имейл test@test.ru и прикрепить к письму тестовый файл, который не имеет отношения к тексту письма. Что бы не повторяться, я не буду больше использовать в заголовках ненужные ключи, которые я использовал в предыдущем примере.

$boundary = md5(uniqid(time()));
Ключ boundary – граница, которая разделяет различные части сообщения. Размер значения этого ключа не должен превышать 70 символов и должен включать в себя только буквы, цифры и символы «'()+_,-./:=?». Каждая часть сообщения должна начинаться с двуг дефисов, после которых идет значения ключа границы. Последняя часть сообщения должна выглядеть так "–boundary–", где boundary, это значение переменной $boundary, а не само слово "boundary". На основе хеша мы сиздаем значение границы. Можете создавать её любым другим способом. Главное, что бы значение отвечало требованиям наведенным выше. Некоторые люди ошибочно считают, будто boundary должно начинаться с двух дефисов. Это не так, с двух дефисов должна начинаться строка, которая содержит boundary, а boundary может к примеру начинаться с двух знаков равности или двух плюсов для уникальности.


$headers[] ="MIME-Version: 1.0";
Указывает версию стандарта.
$headers[] ="Content-Type: multipart/mixed;boundary=\"$boundary\"; type=\"text/html;\"";
А здесь самое интересное. У параметра Content-Type значение по умолчанию text/plain; charset=us-ascii. Когда мы указываем в Content-Type значение multipart мы "сообщаем" MIME, что в письме будут находиться несколько вложений. У типа multipart есть 5 субтипов
1) mixed – означет, что в письмо входят несколько независимых друг от друга частей
2) alternative – говорит, о том, что вложения, передаваемые письмом являются альтернативными копиями друг друга (пример использования будет приведен позже).
3) related – сообщает, что вложения являются частями сообщения, формируя единое целое(пример использования будет приведен позже).
4) parallel - если разные части документа должны просматриваться одновременно;
5) digest - если каждая из частей тела письма имеет тип "message".

type=\"text/html;\" – указание формата письма (HTML текст).
$multipart[]= "–".$boundary;
Обозначает начало части письма
$multipart[]= "Content-Type: text/html; charset=utf-8";
Устанавливаем тип этой части, то есть HTML текст в кодировке utf-8
$multipart[]= "Content-Transfer-Encoding: Quot-Printed";
Ключ Content-Transfer-Encoding – обозначает метод или тип конвертации данных. По умолчанию, если этот ключ не передан, для него присваивается свойство 7bit, что обозначает, что содержимое уже находится в двоичном коде и его конвертация не нужна. Я не буду углубляться в эту тему, так как в мануале по этому параметру написано целых 3 страницы А4. Ну а Quot-Printed – предназначен для представления данных, которые в основном состоят из байтов, что имеют соответственное отображение в символьном наборе ASCII. Если тело сообщения полностью состоит из символов ASCII, то этого говорит, что все символы будут иметь человеко-понятный вид. Это гарантирует содержанию целостность при прохождении различных шлюзов.
$multipart[]= "";
Это пустая строка - раздел между заголовками и телом html-части. Даже если предыдущие 2 параметра (что входят в заголовок) не указаны, все равно после границы должна быть одна пустая строка.
$multipart[]= $text;
Где $text – переменная содержащая HTML текст письма. На пример
$text='<html><head><title>Тестовая страница</title></head><body><img width="314" height="173" border="0" alt="HevyWeb" src="http://www.hevyweb.com.ua/templates/new/images/logo.jpg"><b>Привет мир</b></body></html>';
$multipart[]= "";
Пустая строка-разделитель после текста письма.
$multipart[]="–".$boundary;
Начинается часть, в которой будет описывать прикрепленный файл.
$multipart[]= "Content-Type: application/octet-stream; name=\"".$filename."\"";
Указываем тип прикрепленного вложения. application/octet-stream – говорит о том, что передаваемый файл – бинарный. Другими словами – это приложение либо документ, который должен быть открыт каким либо приложением на вашем компьютере.
$multipart[]= "Content-Transfer-Encoding: base64";
Этот параметр говорит о том, что содержимое файла закодировано при помощи Base64, который выделяет по 6 бит на каждый печатный символ, используя 65-символьный поднабор из US-ASCII. Ладно, не буду влезать в дебри, просто скажу, что этот метод необходим при передаче двоичных данных файла.
$multipart[]= "Content-Disposition: attachment; filename=\"".$filename."\"";
Указываем имя файла, которое увидит получатель, оно может отличатся от имени передаваемого файла на нашем сервере.
$multipart[]= "";
Разделитель между заголовками и телом прикрепленного файла
$multipart[]= chunk_split(base64_encode($filecontent));
Содержимое файла закодированное в кодировке Base64. chunk_split – разбивает строку на куски, что бы привести содержимое в соответствие с форматами стандартов передачи данных (RFC 2045).
А теперь соберем все куски вместе и построит простейшую функцию.

<?
Function mail_to($to, $from, $subj, $text, $files=null){
$boundary = md5(uniqid(time()));
$headers[] ="MIME-Version: 1.0";
$headers[] ="Content-Type: multipart/mixed;boundary=\"$boundary\"; type=\"text/html;\"";
$headers[] ="From: ".$from;
$headers[] ="Reply-To: ".$from;
$headers[] ="Return-Path: ".$from;
$headers[] ="X-Mailer: PHP/" . phpversion();

$multipart[]= "–".$boundary;
$multipart[]= "Content-Type: text/html; charset=utf-8";
$multipart[]= "Content-Transfer-Encoding: Quot-Printed";
$multipart[]= ""; // раздел между заголовками и телом html-части
$multipart[]= $text;
$multipart[]= "";

if ((is_array($files))&&(!empty($files)))
{
foreach($files as $filename => $filecontent)
{
$multipart[]="–".$boundary;
$multipart[]= "Content-Type: application/octet-stream; name=\"".$filename."\"";
$multipart[]= "Content-Transfer-Encoding: base64";
$multipart[]= "Content-Disposition: attachment; filename=\"".$filename."\"";
$multipart[]= "";
$multipart[]= chunk_split(base64_encode($filecontent));
}
}

$multipart[]= "–$boundary–";
$multipart[]= "";
$headers=implode("\r\n", $headers);
$multipart=implode("\r\n", $multipart);
if (mb_detect_encoding($subj, "UTF-8")==FALSE)
$subj= mb_encode_mimeheader($subj,"UTF-8", "B", "\n");

return mail($to, $subj, $multipart, $headers);
}

$to="Test <test@test.ru>";
$from="Test <test1@test.ru>";
$subj="Привет мир!";
$text='<html><head><title>Тестовая страница</title></head><body><img width="314" height="173" border="0" alt="HevyWeb" src="http://www.hevyweb.com.ua/templates/new/images/logo.jpg" /><b>Привет мир</b></body></html>';
$path_to_file=dirname(__FILE__).DIRECTORY_SEPARATOR."text.txt";
$files = array('text.txt' => file_get_contents($path_to_file));

If (mail_to($to, $from, $subj, $text, $files))
{
Echo "Письмо удачно отправлено";
}
Else
{
Echo "Сбой при отправлении письма";
}
?>

На этом сегодня я статью закончу, однако, это не конец. У статьи будет продолжение. Я покажу вам самый сложный пример, который я смог придумать, в нем будет много вложений разного типа и разной иерархии. Ждите продолжения.
Post #: 1
RE: Функция mail: продвинутый анализ - 2011-03-23 08:46:34.543333   
Pupkin-Zade

Сообщений: 9398
Оценки: 1489
Присоединился: 2004-03-10 13:54:16
Какой эпический бред
Ты попробуй с форума типа Хакера делать рассылки такой функцией - у тебя сервак загнется через 10 минут.
Так что херня полная
Post #: 2
RE: Функция mail: продвинутый анализ - 2011-03-23 14:07:09.626666   
Agent Smith

Сообщений: 976
Оценки: 0
Присоединился: 2007-04-10 21:56:49.593333
В этой статье я хотел рассказать как работает функция mail(), а не как сделать рассылку.
И в каком именно месте - бред? Буду очень рад, если напишите конкретно, что не так?:)
Post #: 3
RE: Функция mail: продвинутый анализ - 2011-03-23 14:12:04.126666   
Pupkin-Zade

Сообщений: 9398
Оценки: 1489
Присоединился: 2004-03-10 13:54:16
Не так то, что функция вообще непригодня для промышленного применения.
Post #: 4
RE: Функция mail: продвинутый анализ - 2011-03-23 16:21:30.563333   
Agent Smith

Сообщений: 976
Оценки: 0
Присоединился: 2007-04-10 21:56:49.593333
Вы пытаетесь затроллить тему? Больше конкретики.
Post #: 5
RE: Функция mail: продвинутый анализ - 2011-03-23 23:23:12.443333   
FriLL

Сообщений: 2539
Оценки: 335
Присоединился: 2007-08-11 17:14:26.703333
mail() это чисто так поиграться, на все норм серваках идет отправка через свой smpt

quote:

- $additional_parameters - (необязательный параметр) – дополнительные параметры письма. К сожалению, ни в официальном мануале, ни на сайте W3C, ни на хабре я не нащел всего списка, а также точного значения всех ключей, которые используются в этом параметре, потому не буду блуждать в потемках.

Ну так блин у PHP открыты исходники, вперед и с песней изучать
Post #: 6
RE: Функция mail: продвинутый анализ - 2011-03-24 00:06:44.496666   
Agent Smith

Сообщений: 976
Оценки: 0
Присоединился: 2007-04-10 21:56:49.593333

quote:

ORIGINAL: FriLL

mail() это чисто так поиграться, на все норм серваках идет отправка через свой smpt

quote:

- $additional_parameters - (необязательный параметр) – дополнительные параметры письма. К сожалению, ни в официальном мануале, ни на сайте W3C, ни на хабре я не нащел всего списка, а также точного значения всех ключей, которые используются в этом параметре, потому не буду блуждать в потемках.

Ну так блин у PHP открыты исходники, вперед и с песней изучать
Может вы имели в виду SMTP?:D Но тема не посвящена бенчмаркетингу SMTP vs MIME. Тема посвящена конкретно функции mail(). Зачем вы пытаетесь строить из себя умного, если ни черта толкового сказать не можете? Напишите статью о SMTP, в которой будет чуть больше, чем в официальном мануале, поднимите стандарты RFC и мы обсудим SMTP, раз он вам так дорог.
Post #: 7
RE: Функция mail: продвинутый анализ - 2011-03-24 00:46:22.536666   
rgo

Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
quote:

ORIGINAL: Pupkin-Zade
Не так то, что функция вообще непригодня для промышленного применения.

Да ну и что? Большая часть текста про то, как составить письмо. Вопрос каким путём его скормить MTA – это несколько другой вопрос. Можно самостоятельно на сокетах написать реализацию, можно поступать также как и mail, но пихать sendmail'у не по одному письму за раз, а кучками. Но как бы мы это не делали, всё равно нам придётся сочинять письмо – писать все эти хедеры, кодировать через mime текст/вложения, бла-бла-бла.
quote:

ORIGINAL: Agent Smith
Но тема не посвящена бенчмаркетингу SMTP vs MIME. Тема посвящена конкретно функции mail(). Зачем вы пытаетесь строить из себя умного, если ни черта толкового сказать не можете?

Убери это. Иначе тебя сейчас не будет чмырить только ленивый. Объясню почему:
1. SMTP – это Simple Mail Transfer Protocol, он описывает как клиент может уговорить MTA принять письмо на обработку. Описывает ли он хедеры письма – я чесслово не помню уже, но если и описывает то лишь самые основные типа To:, From:, Cc:, Reply-To:. MIME же описывает как надо оформлять письмо. Протоколу SMTP плевать что лежит в конверте, ему интересны лишь надписи на конверте.
2. Функция mail, так или иначе всё равно работает через SMTP. В *nix'ах она запускает sendmail передавая ему тобою составленное письмо, sendmail же умеет связаться с местным MTA и убедить его переслать письмо дальше. Причём, как правило (или может даже всегда), sendmail разговаривает с MTA по протоколу SMTP. Как там mail работает в вендовсах я не знаю, никогда не запускал php на венде.
Ты же обсуждаешь в статье MIME, а в комментах пытаешься приписать себе "посвящение функции mail". Просто скажи, что тебя не волнует как письмо будет скармливаться местному MTA, скажи, что есть разные способы, они стопицот раз описаны в интернете и никому не интересны. А вот как составить правильное MIME сообщение – это гораздо интереснее.

Ну а если ты хочешь, чтобы они заткнулись, сходи на википедию и почитай про MIME внимательно. Про SMTP тоже почитай, можешь по диагонали, просто чтобы иметь представление: что к чему. И напиши php библиотечку, которая будет кодировать данное письмо с данными вложениями. Причём чтобы можно было настроить её на использование различных типов кодирования (Content-Type:) и прочая и прочая. MIME ведь используется ещё и протоколом HTTP, там тоже есть заголовок Content-Type, и всякие разные способы передавать данные, на разные случаи жизни, чтобы с указанием Content-Length, без указания, или разбивая на кусочки фиксированного размера…
Post #: 8
RE: Функция mail: продвинутый анализ - 2011-03-25 03:42:57.620000   
Agent Smith

Сообщений: 976
Оценки: 0
Присоединился: 2007-04-10 21:56:49.593333
Хоть один нормальный человек, нашелся, который смог понятно изложить свою речь.

По поводу MIME и SMTP - признаю, погорячился.
Post #: 9
Страниц:  [1]
Все форумы >> [Веб-программинг] >> Функция mail: продвинутый анализ







Связаться:
Вопросы по сайту / xakep@glc.ru

Предупреждение: использование полученных знаний в противозаконных целях преследуется по закону.