Отправлять письма через PHP намного проще, чем кажется. Всего-то надо сформировать правильный EML, подключиться к SMTP и отправить письмо. Ну ещё может быть, хотя и не факт, надо где-то как-то залогировать отправку, а то потом потеряют письмо, скажут, что и не было никаких писем. И виноватый опять ты, хотя ты бел и пушист. А ещё бы хорошо сделать хоть какую-то обработку ошибок, а то вдруг эксепшин, или серевер устал, или коннект не пошёл, а тут суперважный клиент. И уж совсем замечательно хранить где-то письма на случай "я потеряль", "мне не дошло", "а вышлите мне ещё раз". А ещё мы хотим отправлять письма на сайте, который видел расцвет динозавров. А ещё... мне кажется, что список ещё может расширяться не хуже нашей вселенной.
Для решения всех этих проблем я решил написать небольшой инструмент — ApMailer.
ApMailer — это небольшая библиотека, единственной целью которой является отправка почты. Я постарался сделать её максимально простой и удобной. Вы можете скачать всего один файл и отправлять письма и из консоли, и из web-скриптов!
Скачайте из репозитория файл mailer.phar или src/lib.php (если не нужна консольная версия). После этого подключите lib.php:
// Если скачали phar
include 'phar:///path/to/mailer.phar/lib.php';
// Если скачали исходный код
include '/path/to/lib.php';
После этого будет доступна функция Mailer()
:
Mailer()->init(include 'config.php');
$message = Mailer()->newHtmlMessage();
$message->setSubject($messageSubject);
$message->setSenderEmail($messageFrom);
$message->addRecipient($messageTo);
$message->addContent(file_get_contents('mail-header.html'));
$message->addContent($messageText);
$message->addContent(file_get_contents('mail-footer.html'));
$message->addRelatedFile('signature.png');
if (isset($_FILES['attachment']['size']) && $_FILES['attachment']['size'] > 0) {
$message->addAttachmentFile(
$_FILES['attachment']['tmp_name'],
$_FILES['attachment']['name'],
$_FILES['attachment']['type']
);
}
Mailer()->sendMessage($message);
Перед отправкой писем Mailer надо проинициализировать. Делается это так:
Mailer()->init($config);
Конфиг представляет из себя многомерный массив, в котором указываются адрес отправителя по умолчанию, хуки для обработки ошибок и ведения логов и транспортёры:
$config = [
'defaultFrom' => 'mymail@example.org',
'onError' => function($error, $message, $transport) { echo $error; },
'afterSend' => function($text, $message, $layer) { echo $text; },
'transports' => [
// Сохранение всех писем в папке
['file', 'dir' => __DIR__ .'/mails'],
// Отправка писем через Yandex, используя SSL и авторизацию
['smtp', 'host' => 'smtp.yandex.ru', 'ssl' => true, 'port' => '465', 'login' => '****@yandex.ru', 'password' => '******'],
],
];
В качестве транспортов можно использовать file
и smtp
. Тип транспорёта всегда должен передаваться первым элементом массива, дальше идут его настройки.
Транспортёр file
сохраняет письмо в виде EML в папку. Доступны следующие настройки:
dir
— папка, а которую будут сохраняться письма. Если предполагается много писем, лучше хранить их с разбивкой по дате 'dir' => strftime('/path/to/mails/%Y/%m/%d')
Транспортёр smtp
отправляет письмо через SMTP. Доступны следующие настройки:
host
— адрес SMTP-сервераssl
— использовать SSL при подключении (обязательно для google, yandex и других популярных сервисов)port
— порт подключения (обычно 25 для подключения без SSL и 465 для подклюения с SSL)login
— логин для авторизации (если логин не указан, то используется подключение без авторизации)password
— пароль для авторизации (не используется, если логин не указан)Хуки:
onError
— срабатывает на ошибку транспортёра (удобно делать лог ошибок отправки писем)afterSend
— срабатывает после отправки письма (удобно делать общий лог отправки писем)Настройка defaultFrom
нужна, чтобы не указывать каждый раз адрес отправителя. Если система не подразумевает работу нескольких человек, которые могут отсылать почту, то этот адрес обычно постоянный.
В качестве примера я сделал форму отправки письма:
Пример письма:
Поскольку библиотека умеет работать через консоль, то можно формировать команду, которая сможет отправлять письма. Единственное, что нужно, наличие скомпилированного бинарника PHP 5.6.
function sendMail($message) {
$keys = array(
'subject' => '-s',
'from' => '-f',
'text' => '-t',
'reciient' => array('-r'),
'to' => array('-r'),
'related' => array('-i'),
'attachment' => array('-a'),
'config' => array('-c'),
);
$args = array();
// Если отправляют HTML
if (isset($message['html'])) {
$args[] = '--html';
// Подключаем шаблон
$textArray = array();
// Header
$textArray[] = '<html><body>';
if (isset($message['html'])) {
$textArray[] = join((array) $message['html']);
}
// Footer
$textArray[] = '</body></html>';
$message['text'] = join($textArray);
}
foreach ($keys as $key => $argument) {
if (!isset($message[$key])) {
continue;
}
if (is_array($argument)) {
$argument = array_shift($argument);
foreach ((array) $message[$key] as $value) {
$args[] = $argument .' '. escapeshellarg($value);
}
} else {
$args[] = $argument .' '. escapeshellarg($message[$key]);
}
}
$command = 'php5.6 /path/to/mailer.phar '. join(' ', $args);
exec($command);
};
А дальше уже можно отправлять письма:
sendMail(array(
'to' => array('someone@exmaple.org', 'someoneelse@exmaple.org'),
'subject' => 'Привет, мир!',
'html' => '<h1>Hello</h1>',
));