Отправка уведомлений через SMTP

Список розділів Кухня Розробка

Опис: Пропозиції, питання, обговорення

#1 Nazar Tokar » 06.09.2013, 14:46

[обновлено 2013-12-24]

На некоторых хостингах отправка сообщений через php sendmail закрыта, потому скрипт может не работать. В ткхи случаях приходится пользоваться smtp, который зарегистрирован у них же на хостинге. Например, такая проблема возникает у популярного нынче Мастерхоста. Сейчас расскажу, как ее исправить.

Для начала регистрируете почтовый ящик на своем домене. В настройках своего почтового ящика в панели управления получаете такие данные:

  • адрес smtp-сервера
  • порт smtp, обычно это 25
  • имя почтового пользователя, чаще всего здесь просто адрес почты
  • пароль

Обратите внимание, что чаще всего имя пользователя это полный адрес электронной почты. Далее создаете новый файл smtp.php с таким содержимым (взято отсюда):

Код: Виділити все
<?php
$mhSmtpMail_Server = "smtp.domain.tld"; // smtp-сервер
$mhSmtpMail_Port = "25"; // порт smtp
$mhSmtpMail_Username = "[email protected]"; // имя пользователя
$mhSmtpMail_Password = "password"; // пароль

function MailSmtp($to, $subject, $message, $headers) {
global $mhSmtpMail_Server, $mhSmtpMail_Port, $mhSmtpMail_Username, $mhSmtpMail_Password;
$mhSmtpMail_localhost  = "localhost";
$mhSmtpMail_newline    = "\r\n";
$mhSmtpMail_timeout    = "30";

$smtpConnect = fsockopen($mhSmtpMail_Server, $mhSmtpMail_Port, $errno, $errstr, $mhSmtpMail_timeout);
$smtpResponse = fgets($smtpConnect, 515);

if(empty($smtpConnect)) {
$output = "Failed to connect: $smtpResponse";
return $output;
} else {
$logArray['connection'] = "Connected: $smtpResponse";
}

fputs($smtpConnect, "HELO $mhSmtpMail_localhost" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['heloresponse'] = "$smtpResponse";

fputs($smtpConnect,"AUTH LOGIN" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['authrequest'] = "$smtpResponse";

fputs($smtpConnect, base64_encode($mhSmtpMail_Username) . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['authmhSmtpMail_username'] = "$smtpResponse";

fputs($smtpConnect, base64_encode($mhSmtpMail_Password) . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['authmhSmtpMail_password'] = "$smtpResponse";

fputs($smtpConnect, "MAIL FROM: $mhSmtpMail_Username" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['mailmhSmtpMail_fromresponse'] = "$smtpResponse";

fputs($smtpConnect, "RCPT TO: $to" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['mailtoresponse'] = "$smtpResponse";

fputs($smtpConnect, "DATA" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['data1response'] = "$smtpResponse";

fputs($smtpConnect, "Subject: $subject\r\n$headers\r\n\r\n$message\r\n.\r\n");
$smtpResponse = fgets($smtpConnect, 515);
$logArray['data2response'] = "$smtpResponse";

fputs($smtpConnect,"QUIT" . $mhSmtpMail_newline);
$smtpResponse = fgets($smtpConnect, 515);
$logArray['quitresponse'] = "$smtpResponse";
}
?>

Файл загружаете в папку со скриптом по адресу /callme/. Далее открываете файл /callme/lib/send.php и после строки

Код: Виділити все
header("Content-Type: text/html; charset=utf-8"); //кодировка

Вставляете код

Код: Виділити все
require "smtp.php";

Ищете строку:

Код: Виділити все
@mail ($to, $title, $mess, $headers);

И заменяете ее на:

Код: Виділити все
MailSmtp ($to, $title, $mess, $headers);

После этого замените переменную $from на почтовый адрес, от которого отправляется сообщение.

Готово.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

Настройка Buyme на отправку сообщений через SMTP

#2 paulo737 » 07.11.2013, 22:29

Опробовал рецепт который указан выше для отправки на почту но не работает. Возможно потому, что на сервере требуется подключаться через зашифрованный канал (SSL/TLS). Подскажите как быть в этом случае. Дело в том что почта для домена прикручена к gmail.
Вы всегда можете купить слепки и наборы для их изготовления на нашем сайте
paulo737 M
Аватар
Вік: 36
Звідки: Украина, Луганск
Репутація: 0
Повідомлення: 3
З нами: 3 роки 10 місяців

#3 Nazar Tokar » 07.11.2013, 22:57

paulo737, не хотите копаться, создайте ящик на мэйлру или яндекс и настройте отправку через него.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#4 paulo737 » 07.11.2013, 23:53

Пример работающего скрипта отправки для SSL/TSL:

Код: Виділити все
<?php
include "libmail.php"; // вставляем файл с классом
$m= new Mail; // начинаем
$m->From( "Василий Пупкин;мой_аккаунт@gmail.com" ); // от кого отправляется почта
$m->To( "_мой_аккаунт[email protected]" ); // кому адресованно
$m->Subject( "Тест скрипта" );
$m->Body( "Ваш заказ принят" );   
$m->Priority(3) ;    // приоритет письма
$m->smtp_on("ssl://smtp.gmail.com","Логин","Пароль", 465);
$m->Send();    // а теперь пошла отправка
?>
Ссылка на файл библиотеки libmail.php

Пример скрипта взят вот здесь. Там есть более подробное описание для других случаев

Додано через 1 годину 30 хвилин:
Возник другой вопрос, как вместо сообщения "Ваш заказ принят" вставить данные из формы которую пользователь заполнил.
Вы всегда можете купить слепки и наборы для их изготовления на нашем сайте
paulo737 M
Аватар
Вік: 36
Звідки: Украина, Луганск
Репутація: 0
Повідомлення: 3
З нами: 3 роки 10 місяців

#5 Nazar Tokar » 08.11.2013, 01:36

paulo737, интересно, но библиотека рассчитана на отправку в кодировке Win-1251, а обычно все работают с UTF-8.

paulo737 написав:вместо сообщения "Ваш заказ принят" вставить данные из формы

В send.php где

Код: Виділити все
for each ... as $value

Сохранять нужные переменные. Например, это добавить перед циклом:

Код: Виділити все
$toSendArray = array();

А это внутри цикла:

Код: Виділити все
if ( ($value == "Номер телефона") || ($value == "Адрес доставки") ) {
$toSendArray[] = $value;
}

Ну и в конце аттачить массив к письму или к уведомлению.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#6 paulo737 » 08.11.2013, 12:49

Спасибо за развернутый ответ.

интересно, но библиотека рассчитана на отправку в кодировке Win-1251, а обычно все работают с UTF-8.
Код: Виділити все
$m= new Mail; // начинаем

Можно заменить для использования UTF-8
Код: Виділити все
$m= new Mail("utf-8");
Вы всегда можете купить слепки и наборы для их изготовления на нашем сайте
paulo737 M
Аватар
Вік: 36
Звідки: Украина, Луганск
Репутація: 0
Повідомлення: 3
З нами: 3 роки 10 місяців

#7 Souz2000 » 18.11.2013, 12:12

Здравствуйте!
В первом сообещние вы описали как делать для скрипта callme, а в случае скрипта buyme где что заменять нужно?
И еще у нас почта привязана к домену, но сделана на gmail'е, в этом случае использовать скрипт отправки для SSL/TSL?
Заранее спасибо!
Souz2000
Репутація: 0
Повідомлення: 2
З нами: 3 роки 10 місяців

#8 Nazar Tokar » 18.11.2013, 13:46

Souz2000, в скриптах этих отправка работает практически одинаково.
Странно задавать такие вопросы, просто посмотрите на код.

Если не работает через gmail, настройте на Яндекс.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#9 Souz2000 » 18.11.2013, 15:56

То что отправка работает одинаково это ясно, интересует вот этот момент:
Файл загружаете в папку со скриптом по адресу /callme/. Далее открываете файл /callme/index.php и после строки
В случае с buyme как быть? Например index.php - такого файла нет, есть index.html - но ведь это не оно
Souz2000
Репутація: 0
Повідомлення: 2
З нами: 3 роки 10 місяців

#10 Nazar Tokar » 19.11.2013, 00:55

Souz2000, /lib/send.php
Их там всего несколько папок и несколько файлов, как можно запутаться?
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#11 Ramapriya » 14.01.2014, 09:58

Всем привет...

простите за глупый вопрос... а настройках smtp указывать, например, gmail?
Ramapriya
Репутація: -1
Повідомлення: 1
З нами: 3 роки 8 місяців

#12 Nazar Tokar » 14.01.2014, 11:24

Ramapriya, попробуйте в гугле ввести "smtp gmail".
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#13 urok » 09.02.2014, 14:09

установлен Buyme в файле buyme\lib\send.php не было строки
header("Content-Type: text/html; charset=utf-8"); //кодировка
добавил её после <?php
получилось вот так
Код: Виділити все
<?php
header("Content-Type: text/html; charset=utf-8"); //кодировка
require "smtp.php";

закомментировал
//@mail ($to, $title, $mess, $headers);
ниже вставил это
MailSmtp ($to, $title, $mess, $headers);

тут сделал так $from = "адрес@почты.отправителя".$HTTP_HOST; // отправитель

в итогах пишет, что отправлено нормально. СМС приходит, а письма нет.
Сам ящик отправителя проверял, в аутлуке письмо приходит.
urok
Репутація: 1
Повідомлення: 5
З нами: 3 роки 7 місяців

#14 Nazar Tokar » 10.02.2014, 01:39

urok, нужно так

Код: Виділити все
$from = "адрес@почты.отправителя";

PS: я мог бы понимать вас лучше, если бы вы использовали знаки препинания. Например, запятые и точки.

urok написав:Сам ящик отправителя проверял, в аутлуке письмо приходит.

Эту фразу я не понял. Если письмо приходит, в чем тогда вопрос.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#15 urok » 10.02.2014, 04:50

исправил на
Код: Виділити все
$from = "адрес@почты.отправителя";
не помогло

Назар Токарь написав:Эту фразу я не понял. Если письмо приходит, в чем тогда вопрос.
ящик отправителя настроил в оутлоке и отправил на адрес получателя , письмо пришло
а со скрипта не приходит :wink:
urok
Репутація: 1
Повідомлення: 5
З нами: 3 роки 7 місяців

#16 Nazar Tokar » 10.02.2014, 10:33

urok, ну тогда проблема в настройках, ищите ошибку.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#17 urok » 10.02.2014, 15:03

Дядька Назар, похоже мне без вас не справиться, целый день мучаюсь и не работает. Может вы выложите рабочие файлы. так как тут и ошибаться не где

еще раз все настройки, smtp.php исправляю верхние 4 строчки, ниже ничего не трогаю
Код: Виділити все
$mhSmtpMail_Server = "smtp.yandex.ru"; // smtp-сервер
$mhSmtpMail_Port = "25"; // порт smtp
$mhSmtpMail_Username = "ящик-отправителя@yandex.ru"; // имя пользователя
$mhSmtpMail_Password = "пароль от почты"; // пароль

в файле send.php исправляю только эти строчки
Код: Виділити все
require "smtp.php";
$to = "ящик-получателя@mail.ru";
$from = "ящик-отправителя@yandex.ru";
MailSmtp($to, $title, $mess, $headers);

file send.php
Спойлер
<?php
// Buyme 1.3.5 2013 by Nazar Tokar
// dedushka.org * nazartokar.com * [email protected]
require "smtp.php";
//адрес почты для отправки уведомления
$to = "ящик-получателя@mail.ru"; //несколько ящиков могут перечисляться через запятую

$HTTP_HOST = parse_url('http://'.$_SERVER["HTTP_HOST"]);
$HTTP_HOST = str_replace(array("http://","www."),"", $HTTP_HOST['host']);
$from = "ящик-отправителя@yandex.ru"; // отправитель

// данные для отправки смс

$sms["id"] = "";
$sms["key"] = "";
$sms["log"] = "";
$sms["pss"] = "";
$sms["frm"] = "callme"; // добавьте новую подпись в смс-шлюзе и дождитесь апрува
$sms["num"] = ""; // ваш номер в формате без + (79218886622)
$sms["prv"] = "sms.ru"; // на выбор: sms.ru, infosmska.ru, bytehand.com, sms-sending.ru, smsaero.ru

function uc ($s)
{
$s = urlencode($s);
return $s;
}

function gF ($s) // no shit
{
$s = substr( (htmlspecialchars($_GET[$s])), 0, 500);
if (strlen($s) > 1) return $s;
}

function echoResult ($result, $class, $time, $message) // выводим данные json
{
echo '{
"result": "'.$result.'",
"cls": "'.$class.'",
"time": "'.$time.'",
"message": "'.$message.'" }';
exit();
}

function sendSMS ($to, $msg){
global $sms;

$u['sms.ru'] = "sms.ru/sms/send?api_id=".uc($sms["key"])."&to=".uc($sms["num"])."&text=".uc($msg);
$u['bytehand.com'] = "bytehand.com:3800/send?id=".uc($sms["id"])."&key=".uc($key)."&to=".uc($sms["num"])."&partner=callme&from=".uc($sms["frm"])."&text=".uc($msg);
$u['sms-sending.ru'] = "lcab.sms-sending.ru/lcabApi/sendSms.php?login=".uc($sms["log"])."&password=".uc($sms["pss"])."&txt=".uc($msg)."&to=".uc($sms["num"]);
$u['infosmska.ru'] = "api.infosmska.ru/interfaces/SendMessages.ashx?login=".uc($sms['log'])."&pwd=".uc($sms["pss"])."&sender=SMS&phones=".uc($sms["num"])."&message=".uc($msg);
$u['smsaero.ru'] = "gate.smsaero.ru/send/?user=".uc($sms["log"])."&password=".md5 (uc($sms["pss"]))."&to=".uc($sms["num"])."&text=".uc($msg)."&from=".uc($sms["frm"]);

@$r = file_get_contents("http://".$u[$sms["prv"]]);
}

$l["sent"] = "Заказ уже был отправлен";
$l["err"] = "Пожалуйста, заполните все поля";
$l["ok"] = "Спасибо, заказ принят. Ждите звонка";
$l["title"] = "BuyMe: новый заказ";
$l["footer"] = "<p><a href='http://dedushka.org/tag/buyme/'>Следите</a> за обновлениями скрипта.<br>Спасибо за использование BuyMe.</p>";

function addToMess ($c, $o)
{
$s = "<p><b>".$c."</b>:<br>".$o."</p>";
return $s;
}

function getOptions ($o) // get fields
{
$captions = $_GET["cs"];
$options = $_GET["os"];
$opts = "";
$i = 0;

if ($o == 1) {
foreach ($options as $value)
{
if ( strlen($value) > 1 ) {
if ($captions[$i] == "url")
{
if (strlen($value) < 60)
{
$opts .= addToMess($captions[$i], $value);
}
else
{
$link = "<a href='".$value."'>".substr($value, 0, 60)."...</a>";
$opts .= addToMess($captions[$i], $link);
}
}
else
{
$opts .= addToMess($captions[$i], $value);
}
}
$i++;
}
} else {
foreach ($options as $value)
{
if ( strlen($value) > 1 ) {
$opts .= $captions[$i]."(".$value.") ";
}
$i++;
}
}
return $opts;
}

function translit ($str) // translit by programmerz.ru
{
$tr = array("А"=>"A","Б"=>"B","В"=>"V","Г"=>"G","Д"=>"D","Е"=>"E","Ё"=>"E","Ж"=>"J","З"=>"Z","И"=>"I","Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N","О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T","У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"C","Ч"=>"4","Ш"=>"SH","Щ"=>"SC","Ъ"=>"","Ы"=>"Y","Ь"=>"","Э"=>"E","Ю"=>"U","Я"=>"YA","а"=>"a","б"=>"b","в"=>"v","г"=>"g","д"=>"d","е"=>"e","ё"=>"e","ж"=>"j","з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l","м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r","с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h","ц"=>"c","ч"=>"4","ш"=>"sh","щ"=>"sch","ъ"=>"y","ы"=>"y","ь"=>"","э"=>"e","ю"=>"u","я"=>"ya");
return strtr($str,$tr);
}

// далее можно не трогать

$time = time(); // время отправки
$interval = $time - gF("time");
if ($interval < 1) // если прошло менее (сек)
{
echoResult('err', 'b1c-err', '', $l["sent"]);
} else {

$get_data = $_GET["cs"];

if (count($get_data) > 1) // data to send
{
$ip = $_SERVER['REMOTE_ADDR'];
$prd = gF("prd");

@$geo = file_get_contents('http://freegeoip.net/json/'.$ip);
@$geo = json_decode($geo, true);

$title = $l["title"];
$title = "=?UTF-8?B?".base64_encode($title)."?=";
$mess = "<h3>Заказ на ".$prd."</h3><div style='background:#fffce8;border:1px solid #cecece;padding:10px 10px 0'>";

$mess .= getOptions(1);

$mess .= addToMess("IP",$ip);
$mess .= addToMess("Откуда запрос",(($geo['city'])." (".($geo['country_name']).")" ));

$mess .= "</div>".$l["footer"];

$headers = "Content-type: text/html; charset=utf-8 \r\n";
$headers .= "From: BuyMe 1.3.5 <".$from.">\r\n";

$sms["msg"] = substr( translit($prd.",".(getOptions(0))), 0 ,160 );

MailSmtp($to, $title, $mess, $headers);
if ( ($sms["id"] != "") || ($sms["key"] != "") || ($sms["log"] != "") )
{
@sendSMS($num, $sms["msg"]);
}
echoResult("ok", "b1c-ok", $time, $l["ok"]);
} else {
echoResult("err", "b1c-err", "", $l["err"]);
}
}
?>
urok
Репутація: 1
Повідомлення: 5
З нами: 3 роки 7 місяців

#18 foxsnort » 10.02.2014, 15:08

Друзья, подскажите, пожалуйста! Я новичок в этом, проблему гуглил, но так и не нашел решение((
Ситуация следующая: сервер на debian 7, настроил exim4, тестовое письмо получаю, все ок. Поставил скрипт callme, все настройки сделал по инструкции в начале этой темы. НО письма не приходят. Стал разбираться и вот что записывается в логах:

Спойлер
[Sat Feb 08 16:21:31 2014] [error] [client х.х.х.х] PHP Warning: fsockopen(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /www/callme/lib/smtp.php on line 14, referer: http://mydomain.com/
[Sat Feb 08 16:21:31 2014] [error] [client х.х.х.х] PHP Warning: fsockopen(): unable to connect to smtp.domain.tld:25 (php_network_getaddresses: getaddrinfo failed: Name or service not known) in /www/callme/lib/smtp.php on line 14, referer: http://mydomain.com/
[Sat Feb 08 16:21:31 2014] [error] [client х.х.х.х] PHP Warning: fgets() expects parameter 1 to be resource, boolean given in /www/callme/lib/smtp.php on line 15, referer: http://mydomain.com/

Предполагаю, что косяк в настройках файла smtp.php?
foxsnort
Репутація: 0
Повідомлення: 2
З нами: 3 роки 7 місяців

#19 Nazar Tokar » 10.02.2014, 15:39

urok, ну на первый взгляд все правильно. А попробуйте закомментировать все строки с get_file_contents. У вас на хостинге может быть выключена эта функция, такое иногда бывает. Ну или банально на яндекса запрещена отправка через smtp для вашего ящика.

foxsnort, на хостинге запрещены эти функции, по которым варнинги. Нужно их попросить включить хостера. Ну или самому настроить.
Читайте твітер.
Nazar Tokar M
Автор теми, Администратор
Аватар
Звідки: Україна
Репутація: 148
Повідомлення: 2501
Теми: 100
З нами: 4 роки 6 місяців

#20 foxsnort » 10.02.2014, 17:18

Назар Токарь, я так понимаю, что запрещена функция fsockopen? А включается она в php.ini строкой allow_url_fopen = On?
foxsnort
Репутація: 0
Повідомлення: 2
З нами: 3 роки 7 місяців

Наст.

Повернутись в Розробка

Хто зараз на форумі (базується на активності користувачів за останні 30 хвилин)

Зараз переглядають цей розділ: 5 гостей