25 июля 2009 г.

Отправка писем с сайта через PHP

Часто приходится реализовать отправку письма прямо с сайта. Ну, чтобы пользователь мог написать Вам сообщение прямо на страничке Вашего сайта, не используя почтовую программу.
Сделать такую отправку несложно. Для этого необходимо, чтобы Ваш хостинг поддерживал PHP.
Собственно отправка письма осуществляется одной командой PHP:



mail (<на какой почтовый адрес отправить>, <тема (название) письма>, <тело письма>, <заголовки сообщения>)
Разумеется, для отправки на страничке надо нарисовать форму – в которой будут поля для самого сообщения, имени пользователя и его e-mail (Вы ведь хотите знать, кому отсылать ответ :)
Итак, предположим что у нас есть форма (а создать ее действительно несложно), на которой имеется три текстовых поля:
- email – для почтового адреса пользователя
- fio – для его ФИО, или просто для имени
- data – для тела сообщения
Поле для темы письма я специально упустил. Ведь обычно написать тему письма человека заставляют именно разработчики сайта; хотя тема, по сути, не нужна – ведь в сообщении пользователь уже и так написал все, что хотел. В общем, отсутствие темы – это хорошее юзабилити, а саму тему письма можно сформировать программно из тех данных, что ввел пользователь.
Итак, у нас есть веб-форма с необходимыми полями, и мы передаем из нее данные при помощи метода POST.
Теперь обработаем эти данные с помощью PHP, и отправим письмо.
Простейший PHP-скрипт для отправки письма будет выглядеть следующим образом:


<?php
if (mail("test@gmail.com", "Письмо с сайта от $name", $_POST['data'], "From: $email"))
{
echo "Спасибо за отправленное сообщение.";
}
else
{
echo "Извините, но из-за технических проблем письмо отправить не удалось.";
}
?>


Вкратце разберем этот скрипт.
Команда if позволяет нам среагировать на отправку. Если все нормально, и письмо отправлено – мы выведем пользователю сообщение, что письмо отправлено.
Если вдруг возникли проблемы – напишем, что письмо не отправлено. Это, кстати, тоже хорошее юзабилити – а то бывает, что на некоторых сайтах после отправки письма тебя сразу перебросят на главную – и ты толком не понимаешь, то ли твое письмо ушло по назначению, то ли отправилось в мусорную корзину.
Теперь о строчке


mail("test@gmail.com", "Письмо с сайта от $name", $_POST['data'], "From: $email")
- В первом параметре задан адрес, на который отправится письмо.
- Во втором параметре сформирован т.н. тема письма – то есть строка, которая в почтовом клиенте отображается в поле Subject.
- В третьем параметре передается непосредственно тело письма – то есть само сообщение.
- В четвертом параметре формируется служебный заголовок. Вообще-то служебный заголовок может быть не один – но здесь мы просто сформировали строку, в которой прописан обратный почтовый адрес отправителя.
Отмечу, что приведенный код работает – но подходит он далеко не всегда.
Если письма, отправленные таким методом, будут приходить Вам на Gmail – то все нормально, Gmail будет их отображать корректно.
Если же эти письма будут приходить в почтовую программу, то скорее всего возникнет проблема с кодировками. И в почтовике письма будут отображаться «кракозябрами» – а Вам каждый раз придется подбирать правильную кодировку (ну а заголовок письма вообще никогда не будет перекодирован правильно).
(Если Вас интересует, почему Gmail все отображает корректно – то все просто. В нем встроены весьма интеллектуальные алгоритмы декодирования – и они самостоятельно проводят декодирование для каждого письма. В большинстве почтовых программ таких алгоритмов нет – и если в письме кодировка не указана в явном виде, то ее надо подбирать вручную.)
Но пойдем дальше.
Чтобы в почтовой программе все отображалось как положено, нам надо перед отправкой письма провести ряд перекодировок.
Во-первых, надо грамотно закодировать текст письма, а также явно указать кодировку. Во вторых, надо закодировать заголовок, который отображается в поле Subject. (Не буду сильно вдаваться в детали, но так уж повелось, что заголовок кодируется ОТДЕЛЬНО от тела письма.)
Ну что ж, приступим (ниже приведен готовый к использованию код, так что если не хотите разбираться в деталях, можете сразу перейти к нему).
Как правило, веб-странички на русском оформляются в кодировке CP-1251 (русская кодировка Windows). А почтовые письма ходят в кодировке KOI8-R.
Для перекодировки используем всего одну функцию:
convert_cyr_string (<текст, который надо перекодировать>,w,k)
Где w и k – это задание кодировок, то есть «из CP-1251 в KOI8-R».
Что касается кодирования заголовка письма, то заголовок должен кодироваться по-особому, в т.н. MIME-кодировке.
Для перекодирования в MIME-кодировку используется функция
base64_encode(<текст, который надо перекодировать>)
Надо отметить, что при кодировании заголовка надо явно указать кодировку, из которой было проведено перекодирование. Ниже, в рабочем коде, все это уже проделано.
Итак, рабочий код, который отправляет письма с сайта с помощью PHP:

<?php
/*формируем переменные, которые содержат данные, полученные с html-формы*/
$email = $_POST['email'];
$name = $_POST['fio'];
$to = "test@gmail.com"; // адрес, куда слать письмо
// формируем Тему письма
$subject = "Письмо с сайта от $name";
// Конвертируем ее в кодировку KOI8-R
$subject = convert_cyr_string ($subject,w,k);
/* А теперь конвертируем ее в MIME-кодировку, заодно указывая, то это KOI8-R */
$subject = '=?koi8-r?B?'.base64_encode($subject).'?=';
// Конвертируем тело письма в KOI8-R
$msg = convert_cyr_string ($_POST['data'],w,k);
/* Составляем заголовки – служебную часть письма, где указываем тип кодировки и тип самого письма (plain text, т.е. простой текст) */
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/plain; charset=koi8-r' . "\r\n";
$headers .= 'To: '.$to. "\r\n";
$headers .= 'From:' .$email. "\r\n";
// Отправляем письмо
if (mail($to,$subject, $msg, $headers))
{
echo "Спасибо за отправленное сообщение.";
}
else
{
echo "Извините, но из-за технических проблем письмо отправить не удалось.";
}
?>


P.S. Если Вы – новичок в PHP, но понимаете, что знание этого языка может Вам здорово помочь при создании сайтов (а оно точно может – уж поверь на слово!), то могу порекомендовать Вам неплохой курс Евгения Попова.
Называется «PHP+MySQL для начинающих». В видео-формате, с толковыми объяснениями и примерами. Для новичков – самое то. Да и стоит немного – всего 1800 руб. Хорошая штука, полезная.

P.P.S. Если вдруг возникли какие-то проблемы, или что-то непонятно – пишите в комментариях.

40 комментариев :

  1. Здравствуйте, Александр! прошу Вашей помощи по отправке письма с сайта. Писал Вам на почту, добавил в скайп.

    ОтветитьУдалить
  2. письмо gmail.com не доходит

    ОтветитьУдалить
  3. Спасибо!! Во всем разобралась! все работает!!)))

    ОтветитьУдалить
  4. а если страничка написана на utf-8 тогда как быть? как нужно перекодировать?

    ОтветитьУдалить
  5. а если надо в форму ввести 6 или 7 запрашиваемых полей как тогда форма будет выглядеть?

    ОтветитьУдалить
  6. а можна ли этот скрипт чтоб отправлял не напочту письма а на мабильные телефоны слал смс слышал что через почту тоже можна отправлять смс на мобилы но тока незнаю как если хто знает ответ на мой вапрос напишите на маю почту ynii@list.ru ICQ 609-603-736

    ОтветитьУдалить
  7. Непонятно - документ html с формой и обработчик php написаны в koi8-r. Отправляю письмо на почту с сайта, тема письма нечитаемая, само письмо прекрасно читается. Если меняю кодировку страницы и обработчика на utf-8, то приходит тема письма, но сам текст письма нечитаемый. Что за...?

    ОтветитьУдалить
  8. Народ! не парьте себе и окружающим мозг с кодировками! Есть условная WEB - кодировка "UTF-8", вот и используйте её.

    $subject = '=?utf-8?B?'.base64_encode($subject).'?='; //кодировка темы письма

    и

    $headers .= 'Content-type: text/plain; charset=utf-8' . "\r\n"; //кодировка сообщения письма

    ОтветитьУдалить
  9. у меня письмо доходит, но в теле пусто. как быть?

    ОтветитьУдалить
    Ответы
    1. Проверить перед отправкой, что тело не пустое. Понимаю - да, звучит банально. Но поверьте, опыт неоднократно доказывал простую истину - если что-то не работает, то проблемы только две: 1) неверный код, 2) неправильные исходные данные.

      Удалить
    2. Под "телом" понимается "тело сообщения". То есть, переменная $msg (или $message, или как оно у вас названо) не должна быть пустой. Проверьте её на длину строки. Кстати, может быть и такое, что она не передана с html-страницы через POST. Так что проверяйте ещё на этапе разбора POST-параметров.

      Удалить
    3. Спасибо, понял, сейчас буду проверять!

      Удалить
    4. Спасибо, Александр, разобрался, просто допустил опечатку в строке перекодировке, где кодировалась другая пустая переменная. вот так -то.

      p.s. я новичок в php :-)

      Удалить
  10. Я Подкорытова Марина Викторовна обращалась к вам за помощью.Но ответа от Вас не получила.Снова обращаюсь к Вам с просьбой.
    Принять меры по поводу жилья.Я продала свой дом в селе Шмаково,где проживала с двумя несовершеннолетними детьми.
    Продала своей покупательнице Шмаковой О.А.Шмакова должна рассчитаться со мной в 21 ноября 2011 года,но
    до сих пор не рассчиталась.Я подала в суд Кетовский 12 марта 2012года.Суд решил взыскать с гражданки Шмаковой
    деньги в размере 347тыс.286руб.Но пристав Бекишев Сансыбай Кожанович до сих пор не взыскал с гражданке Шмаковой деньги.
    Пояснил тем что:со Шмаковой не чего взыскивать.Я подала снова в суд Кетово 14февраля 2013 года куплю продажи расторгнуть
    моего дома.Судья Артымонова отказала мне расторгнуть купли продажи моего дома.Я осталась без денег, без дома.Живу
    с двумя несовершеннолетними детьми 2 года на улице.Помогите нам пожалуйста разобраться в этой нелегкой ситуации
    и решить эту проблему.Почему суд вынес не правильное решение.Я осталась без денег и своего дома.


    ОтветитьУдалить
    Ответы
    1. Марина Викторовна, вам скорее надо к какому-то правозащитнику, наподобие Алексея Навального - http://navalny.livejournal.com/ А то здесь немного другие вопросы обсуждаются - компьютерные.

      Удалить
  11. Здравствуйте! Подскажите пожалуйста как реализовать, чтоб отправить письмо пользователь мог нескольким адресатам, вводя их e-mail через форму отправки или подгружая отдельным файлом типо мои контакты из Агента или что-то типо того! Это нужно для страницы приведи друзей и получи скидку или бонус, где посетителю предлагается через соц сети и электронную почту позвать своих друзей

    ОтветитьУдалить
    Ответы
    1. Владислав,
      для начала хорошо освойте функцию mail - http://php.net/manual/ru/function.mail.php - она позволяет перечислить несколько получателей письма через запятую.

      А целом - освойте какую-нибудь книгу по PHP. Очень неплохие книги у Кузнецова (изд-во БХВ-Петербург).

      Удалить
    2. То есть просто через запятую, а input type какой задавать этому полю? И через фаил если загружать то как , что использовать? За совет спасибо! Я сейчас Энди Хариса читать начал. Но когда делать, что нибудь начнешь то возникают вопросы, на которых ответа в книжки не найдешь

      Удалить
  12. Здравствуйте Александр. Прошу помочь разобраться со следующей формой.
    HTML

    форма action="send.php" method="POST"
    Ваш отзыв или сообщение
    текстареа cols="100" rows="10" name="msg"/текстареа
    Ваши контактные данные:
    Телефон

    инпут name="phone" size="30" type="text"
    Email

    инпут name="email" size="30" type="text"
    инпут type="submit" value="Отправить"
    инпут type="reset" value="Очистить форму"
    /форма

    PHP



    if (isset($_POST['msg'])) {$mes = $_POST['msg'];};
    if (isset($_POST['phone'])) {$phone = $_POST['phone'];};
    if (isset($_POST['email'])) {$email = $_POST['email'];};

    $to = "example@mail.ru";
    $sub = "Сообщение с сайта";
    function win_to_utf8($msg){
    $msg = convert_cyr_string($mes, 'w','i');
    $msg = utf8_encode ($msg);
    return $msg;
    }
    mail($to,$sub,$msg,'Content-Type: text/plain; charset=utf-8');
    print('Thank You!');


    приходят пустые письма. Если не трудно, прошу помочь.

    ОтветитьУдалить
    Ответы
    1. Ошибка в названии переменных:

      - тело письма записывается в $mes
      - а в mail оно извлекается из несуществующей переменной $msg

      Она вроде как есть - но в функции win_to_utf8. При этом она является локальной для самой функции - то есть вне ее не видна. Да и сама функция, хоть и объявлена, но ни разу не вызывается.

      В общем, старайтесь писать более чистый код, и используйт echo для визуальной проверки во время тестирования.

      Удалить
  13. Уважаемые господа!
    Подскажите если сайт не на движке,а я сам пишу html код,причем пока принципиально не использую css,можно ли реализовать отправку сообщения на мыло с html страницы где посетитель указывает 8-значное число и свой почтовый ящик .Без капчи,без рекламы,а самое главное безопасный для всех участников.Сколько не пробовал не получается.
    Если такое возможно -прошу Вас помочь мне в этом вопросе.

    ОтветитьУдалить
    Ответы
    1. Так как не совсем понятен вопрос, приведите, пожалуйста, пример кода, которым вы пробовали это реализовать. Вы отправляете через php, как я понимаю. Дайте пример - чтобы можно было понять, что конкретно вы хотите сделать (так как непонятно, зачем посетитель должен указать 8-значное число, что вы ему в сообщении хотите отправить, и причём тут css). Итак, пример кода?

      Удалить
    2. форма здесь не публикуется
      в ней : имя мыло сообщение и кнопка отправить

      К ней пробовал разные обработчики из сети.Непомогает
      Я если правильно понимаю это вопрос нескольких минут
      Есть ли место в инете где взять рабочий обработчик или же прошу Вас Господа помогите разово в этой проблеме
      Все потому что в php я новенький а форму хотелось бы уже сейчас
      Не подумайте что я не пытался-неделю бьюсь но никак,хоть не попортить что есть уже.
      Поэтому прошу Вас помогите если есть тот кто снизайдет,а я внемлю.
      Заранее благодарен

      Удалить
  14. все что мне бы хотелось чтобы человек ввел своё имя ,почту,сообщение отправил их мне на почту и остался на той же странице.При этом не используя css

    ОтветитьУдалить
    Ответы
    1. CSS тут вообще ни при чём - оно для оформления страницы. По вашей теме - вот готовый пример - http://www.php-mail.ru/?id=2 (он должен быть полностью помещён в файл с расширением php). Когда его освоите, и захотите чего-то более сложного, прочитайте здесь - http://phpclub.ru/detail/article/mail - а также вот здесь - http://www.php.su/articles/?cat=email&page=001

      Но вашем случае достаточно и первого, готового примера.

      Удалить
    2. я отправил письмо.буду разбираться дальше.спасибо.только не понял зачем указывать от кого отправлено было если я посылаю письмо со своего на свой ящик.
      В любом случае это лучший результат за все время

      Удалить
    3. > не понял зачем указывать от кого отправлено было если я посылаю письмо со своего на свой ящик

      Это ведь только частный случай - "со своего на свой ящик". Обычно - от отправителя к получателю. То есть, должен быть и отправитель, письмо же не может прийти из пустоты. А вообще, если интересно, вот описание почтового протокола - http://ru.wikipedia.org/wiki/SMTP

      Удалить
  15. когда все вместе работает , но если форму вставить на страницу html,а обработчик на другую php тогда пересылка не происходит.И как сделать чтобы после отправки человек попадал на страницу с формой.
    Простите за второе счастье...

    ОтветитьУдалить
  16. Неужели в интернете нет такого:
    index.html вставить такую форму
    mail.php вставить такой обработчик
    а потом прописать где надо свой email,страницу перехода куда должен попадать человек.

    ОтветитьУдалить
  17. > а потом прописать... страницу перехода куда должен попадать человек

    Всё есть - вы просто не потрудились поискать. Для этого надо дописать в php (уже после кода, отправляющего письмо) такие команды:

    header("Location: index.html");
    exit();

    ОтветитьУдалить
  18. Александр я понимаю что вас уже атаковали таким вопросами! Но прошу вас мне помочь вот таким кодом!


    при отправке письма!: "Сообщение отправлено" и "сообщение не отправлено" выводится крякозябрами!!

    ОтветитьУдалить
  19. php

    if (isset($_POST['name'])) {$name = $_POST['name'];}
    if (isset($_POST['email'])) {$email = $_POST['email'];}
    if (isset($_POST['sub'])) {$sub = $_POST['sub'];}
    if (isset($_POST['body'])) {$body = $_POST['body'];}


    $address = "esteticcleanness@cp260693.cpanel.tech-logol.ru";


    $mes = "Имя: $name \nE-mail: $email \nТема: $sub \nТекст: $body";


    $send = mail ($address,$sub,$mes,"Content-type:text/plain; charset = utf-8\r\nFrom:$email");
    if ($send == 'true')
    {
    echo "Сообщение отправлено";
    }
    else
    {
    echo "Сообщение не отправлено";
    }

    ОтветитьУдалить
    Ответы
    1. Как я могу понять, у вас этот код php подгружается к другой части, где есть шапка html-страницы, и какой-то дизайн. Так вот, та страница у вас в одной кодировке (может cp-1251), а вот этот php-файл - в другой (наверное в UTF-8). Это наиболее вероятная причина.

      Удалить
  20. Этот комментарий был удален автором.

    ОтветитьУдалить
  21. да ты правильно понял Александр! но у меня и html и php - в UTF-8! как быть?)

    ОтветитьУдалить
    Ответы
    1. Анатолий, не ленись! Я ведь написал, что с вероятностью 99% не сходится кодировка файлов. Проверь, что у тебя оба на диск записаны в одинаковой кодировке.

      Удалить
  22. спасибо) Александр я посмотрю ! а лень наш страшный враг!удачи)

    ОтветитьУдалить

Примечание. Отправлять комментарии могут только участники этого блога.