Отправка email через HTTPS в PHP: от cURL до Guzzle

Раздел: Взаимодействие с HTTP -> Работа с почтой

Введение в отправку email через HTTPS в PHP

Традиционная функция mail() использует SMTP и не всегда подходит для современных требований безопасности и доставляемости. Альтернативный подход – отправка писем через HTTPS-запросы к REST API специализированных почтовых сервисов (SendGrid, Mailgun, Amazon SES). Это обеспечивает шифрование, аутентификацию и высокую надёжность. В статье рассмотрены основные варианты реализации на PHP.

Наиболее эффективное решение: Guzzle и SendGrid

Библиотека Guzzle предоставляет удобный интерфейс для HTTP-запросов. Отправка через SendGrid требует установки пакета и API-ключа.


// Установка через Composer (выполнить в терминале):
// composer require guzzlehttp/guzzle

require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://api.sendgrid.com/v3/',
    'headers'  => [
        'Authorization' => 'Bearer ' . getenv('SENDGRID_API_KEY'),
        'Content-Type'  => 'application/json',
    ]
]);

$emailData = [
    'personalizations' => [[
        'to' => [['email' => 'recipient@example.com']]
    ]],
    'from' => ['email' => 'sender@example.com'],
    'subject' => 'Тестовое письмо',
    'content' => [['type' => 'text/plain', 'value' => 'Привет! Это тест.']]
];

try {
    $response = $client->post('mail/send', [
        'json' => $emailData
    ]);
    
    if ($response->getStatusCode() === 202) {
        echo "Письмо успешно отправлено";
    }
} catch (\GuzzleHttp\Exception\ClientException $e) {
    $status = $e->getResponse()->getStatusCode();
    $body = (string) $e->getResponse()->getBody();
    echo "Ошибка $status: $body";
}

Проблемы и их решение

  • Отсутствует Composer или не установлен Guzzle – проверьте наличие composer.json и выполните установку.
  • Ошибка аутентификации (401) – убедитесь, что API-ключ корректен и экспортирован в переменную окружения SENDGRID_API_KEY.
  • SSL-ошибка – в большинстве случаев Guzzle обрабатывает сертификаты автоматически, но при работе в изолированной среде может потребоваться указать путь к CA bundle через параметр verify.

Как отправить email через HTTPS без внешних библиотек? Вариант с cURL

Если установка Composer невозможна, используется нативная библиотека cURL. Она присутствует в большинстве PHP-сборок.


$apiKey = getenv('SENDGRID_API_KEY');
$url = 'https://api.sendgrid.com/v3/mail/send';

$data = [
    'personalizations' => [[
        'to' => [['email' => 'recipient@example.com']]
    ]],
    'from' => ['email' => 'sender@example.com'],
    'subject' => 'Тест cURL',
    'content' => [['type' => 'text/plain', 'value' => 'Отправлено через cURL.']]
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $apiKey,
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($httpCode === 202) {
    echo "Письмо отправлено (HTTP $httpCode)";
} else {
    echo "Ошибка: HTTP $httpCode, ответ: " . $response;
}

curl_close($ch);

Типичные ошибки cURL

  • CURL error 60 – SSL certificate problem – отключите проверку (только для теста!) установкой CURLOPT_SSL_VERIFYPEER = false или укажите правильный CA bundle.
  • Ошибка таймаута – добавьте curl_setopt($ch, CURLOPT_TIMEOUT, 30);.
  • Некорректный JSON – проверьте структуру данных перед кодированием.

Как отправить email через HTTPS используя только встроенные функции PHP? Вариант с file_get_contents и stream context

Для простых запросов можно обойтись без cURL, применив функцию file_get_contents() с контекстом потока. Этот метод работает только при включённой директиве allow_url_fopen.


$apiKey = getenv('SENDGRID_API_KEY');
$url = 'https://api.sendgrid.com/v3/mail/send';

$data = [
    'personalizations' => [[
        'to' => [['email' => 'recipient@example.com']]
    ]],
    'from' => ['email' => 'sender@example.com'],
    'subject' => 'Тест file_get_contents',
    'content' => [['type' => 'text/plain', 'value' => 'Отправлено без cURL.']]
];

$options = [
    'http' => [
        'method'  => 'POST',
        'header'  => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json'
        ],
        'content' => json_encode($data),
        'ignore_errors' => true
    ],
    'ssl' => [
        'verify_peer'      => true,
        'verify_peer_name' => true
    ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
$httpResponseHeader = $http_response_header;

// Поиск HTTP-статуса в заголовках
if (strpos($httpResponseHeader[0], '202') !== false) {
    echo "Письмо отправлено";
} else {
    echo "Ошибка: " . implode('\n', $httpResponseHeader);
}

Проблемы и ограничения

  • allow_url_fopen отключена – метод не сработает. Используйте cURL или Guzzle.
  • Трудности с обработкой ошибок$http_response_header не всегда даёт полную информацию. Для надёжности применяйте проверку кода ответа через парсинг первой строки.
  • SSL-сертификаты – при ошибках верификации укажите 'verify_peer' => false (только для отладки).

Как отправить email через HTTPS с помощью PHPMailer и REST API?

PHPMailer – популярная библиотека для работы с почтой, но она ориентирована на SMTP. Для отправки через HTTPS можно использовать её в паре с обёрткой над REST API, например, phpmailer/phpmailer совместно с кастомным транспортом. Однако предпочтительнее отдельные HTTP-клиенты. В качестве альтернативы – подключить API напрямую через Guzzle внутри обработчика PHPMailer.


// Пример отправки через SendGrid с использованием PHPMailer (транспорт не задан)
// Фактически такой код дублирует функциональность Guzzle. Лучше использовать готовый SDK.

Полноценная интеграция PHPMailer с HTTPS-сервисами выходит за рамки статьи, но упомянуть стоит для полноты картины.

Расширенные примеры отправки email через HTTPS

Отправка с вложением (Guzzle + SendGrid)

Пример

$emailData = [
    'personalizations' => [[
        'to' => [['email' => 'recipient@example.com']]
    ]],
    'from' => ['email' => 'sender@example.com'],
    'subject' => 'Письмо с файлом',
    'content' => [['type' => 'text/plain', 'value' => 'Смотри вложение.']],
    'attachments' => [[
        'content' => base64_encode(file_get_contents('document.pdf')),
        'filename' => 'document.pdf',
        'type' => 'application/pdf',
        'disposition' => 'attachment'
    ]]
];

$response = $client->post('mail/send', ['json' => $emailData]);
echo $response->getStatusCode() === 202 ? 'Успех' : 'Ошибка';
// При успехе:
HTTP 202

Отправка нескольким получателям (cURL)

Пример

$data['personalizations'][0]['to'] = [
    ['email' => 'user1@example.com'],
    ['email' => 'user2@example.com']
];
// Остальной код без изменений
// Успех – два письма уйдут одновременно

Асинхронная отправка через Guzzle с Promise

Пример

use GuzzleHttp\Promise;

$promises = [];
foreach ($recipients as $email) {
    $promises[] = $client->postAsync('mail/send', [
        'json' => [
            'personalizations' => [['to' => [['email' => $email]]]],
            'from' => ['email' => 'sender@example.com'],
            'subject' => 'Асинхронная отправка',
            'content' => [['type' => 'text/plain', 'value' => 'Тест асинхронности']]
        ]
    ]);
}

$results = Promise\unwrap($promises);
foreach ($results as $result) {
    echo $result->getStatusCode() . "\n";
}
202
202
...

Отправка через Mailgun (альтернативный сервис)

Пример

$domain = 'sandbox.mailgun.org';
$apiKey = getenv('MAILGUN_API_KEY');

$client = new Client(['base_uri' => "https://api.mailgun.net/v3/$domain/"]);
$response = $client->post('messages', [
    'auth' => ['api', $apiKey],
    'form_params' => [
        'from'    => 'sender@example.com',
        'to'      => 'recipient@example.com',
        'subject' => 'Привет от Mailgun',
        'text'    => 'Тестовое сообщение'
    ]
]);
echo $response->getStatusCode();
200

Обработка специфических HTTP-ошибок (Guzzle)

Пример

try {
    $response = $client->post('mail/send', ['json' => $emailData]);
} catch (\GuzzleHttp\Exception\ClientException $e) {
    $response = $e->getResponse();
    $statusCode = $response->getStatusCode();
    $errorBody = json_decode((string) $response->getBody(), true);
    
    switch ($statusCode) {
        case 400:
            echo "Некорректный запрос: " . ($errorBody['errors'][0]['message'] ?? 'неизвестно');
            break;
        case 401:
            echo "Неверный API-ключ";
            break;
        case 429:
            echo "Превышен лимит запросов";
            break;
        default:
            echo "Ошибка $statusCode";
    }
}
- Php mail (отправка почты в php)
- Php mail https (отправка email через https в php)
- Php mail sender (отправитель почты php)
- Message php (отправка сообщений в php)
- отправить почту php (отправка почты в php)

Отправка email через HTTPS в PHP - comments

En
Php mail https (php)