По умолчанию в Laravel 8 предлагают отправлять электронную почту через почтовый API на базе библиотеки SwiftMailer (обратите внимание, что на момент перевода статьи библиотека SwiftMailer является более неподдерживаемой и в Larevel 9 используют ее следующую версию Symfony Mailer), которая изначально встроена в Laravel 8. Обычно в web-приложениях на базе PHP для отправки писем используется функция mail(), но в данной статье будет описан алгоритм использования пакета PHPMailer. PHPMailer опенсорсный пакет - его легко устанавливать и использовать в приложениях. Он включает в себя большое количество фич таких как возможность множественной отправки писем с параметрами To, CC, BCC, и Reply-to-addresses, прикрепления как non-inline так и inline вложений, он также защищает от Header Injection атак в соответствии со стандартами безопасности, что делает его использование максимально безопасным.

В данной статье будет описано как отправлять письма с помощью PHPMailer из приложений Laravel 8 через SMTP серверы, являющиеся наиболее рекомендованными для отправки электронных писем из скриптов.

Содержание

  • Отправка электронных писем с использованием PHPMailer из Laravel 8

    • Установка пакета PHPMailer

    • Создание контроллера PHPMailerController.php

    • Создание маршрутов для PHPMailer

    • Создание представления формы отправки писем с помощью PHPMailer

  • Настройка отправки писем через Gmail SMTP сервер

  • Заключение

Отправка электронных писем с использованием PHPMailer из Laravel 8

Установка пакета PHPMailer

Для установки пакета PHPMailer в приложение Laravel 8 воспользуемся пакетным менеджером composer. Мы также можем использовать установщик Laravel  (Laravel Installer). Откроем командную строку и введем в нее:

composer require phpmailer/phpmailer
Процесс установки пакета PHPMailer
Процесс установки пакета PHPMailer

Чтобы удостовериться в том, что пакет PHPMailer был действительно установлен, после выполнения команды проверим файл composer.json, который находится в корневом каталоге проекта.

Файл composer.json
Файл composer.json

Следующим шагом создадим контроллер для отправки писем. В этом контроллере будет содержаться скрипт конфигурации PHPMailer и SMTP.

Создание контроллера PHPMailerController.php

Создадим файл контроллера с именем PHPMailerController.php выполнив команду:

php artisan make:controller PHPMailerController

Для начала для работы с PHPMailer и SMTP нам необходимо объявить классы PHPMailer и Exception и описать функции взаимодействия с ними.

use PHPMailer\PHPMailer\PHPMailer;  
use PHPMailer\PHPMailer\Exception;

Откроем созданный файл PHPMailerController.php и вставим в него представленный ниже код.

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
 
class MailerController extends Controller {
 
    // =============== [ Email ] ===================
    public function email() {
        return view("email");
    }
 
 
    // ========== [ Compose Email ] ================
    public function composeEmail(Request $request) {
        require base_path("vendor/autoload.php");
        $mail = new PHPMailer(true);     // Passing `true` enables exceptions
 
        try {
 
            // Email server settings
            $mail->SMTPDebug = 0;
            $mail->isSMTP();
            $mail->Host = 'smtp.example.com';             //  smtp host
            $mail->SMTPAuth = true;
            $mail->Username = 'user@example.com';   //  sender username
            $mail->Password = '**********';       // sender password
            $mail->SMTPSecure = 'tls';                  // encryption - ssl/tls
            $mail->Port = 587;                          // port - 587/465
 
            $mail->setFrom('sender@example.com', 'SenderName');
            $mail->addAddress($request->emailRecipient);
            $mail->addCC($request->emailCc);
            $mail->addBCC($request->emailBcc);
 
            $mail->addReplyTo('sender@example.com', 'SenderReplyName'); // sender email, sender name
 
            if(isset($_FILES['emailAttachments'])) {
                for ($i=0; $i < count($_FILES['emailAttachments']['tmp_name']); $i++) {
                    $mail->addAttachment($_FILES['emailAttachments']['tmp_name'][$i], $_FILES['emailAttachments']['name'][$i]);
                }
            }
 
 
            $mail->isHTML(true);                // Set email content format to HTML
 
            $mail->Subject = $request->emailSubject;
            $mail->Body    = $request->emailBody;
 
            // $mail->AltBody = plain text version of email body;
 
            if( !$mail->send() ) {
                return back()->with("failed", "Email not sent.")->withErrors($mail->ErrorInfo);
            }
            
            else {
                return back()->with("success", "Email has been sent.");
            }
 
        } catch (Exception $e) {
             return back()->with('error','Message could not be sent.');
        }
    }
}

Необходимо отметить, что перед отправкой письма нужно заменить значения переменных инициирующих отправителя (в коде в комментариях отмечены как: username, password, sender email, sender name) на персональные.

После того как код был скопирован в контроллер, необходимо добавить маршруты в файле web.php.

Создание маршрутов для PHPMailer

Теперь добавим указанный ниже код в файл web.php для создания маршрутов. Их будет два: первый (использующий метод GET) нужен для загрузки представления формы, через которую будем отправлять письма; второй (использующий метод POST) - для отправки данных.

<?php
 
use App\Http\Controllers\PHPMailerController;
use Illuminate\Support\Facades\Route;
 
Route::get("email", [PHPMailerController::class, "email"])->name("email");
Route::post("send-email", [PHPMailerController::class, "composeEmail"])->name("send-email");

Создание представления формы отправки писем с помощью PHPMailer

На данном этапе создадим файл представления с именем email.blade.php в папке resources/views с формой для создания и отправки писем. Копируем и вставляем указанный ниже HTML код формы.

<!doctype html>
<html lang="en">
  <head>
    <title>Send Email Using PHPMailer in Laravel</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  </head>
  <body>
      <div class="container pt-5 pb-5">
        <div class="row">
            <div class="col-xl-6 col-lg-6 col-sm-12 col-12 m-auto">
                <form action="{{route('send-email')}}" method="POST" enctype="multipart/form-data">
                    @csrf
                    <div class="card shadow">
 
                        @if(Session::has("success"))
                            <div class="alert alert-success alert-dismissible"><button type="button" class="close">&times;</button>{{Session::get('success')}}</div>
                        @elseif(Session::has("failed"))
                            <div class="alert alert-danger alert-dismissible"><button type="button" class="close">&times;</button>{{Session::get('failed')}}</div>
                        @endif
 
                        <div class="card-header">
                            <h4 class="card-title">Send Email Using PHPMailer</h4>
                        </div>
 
                        <div class="card-body">
                            <div class="form-group">
                                <label for="emailRecipient">Email To </label>
                                <input type="email" name="emailRecipient" id="emailRecipient" class="form-control" placeholder="Mail To">
                            </div>
 
                            <div class="form-group">
                                <label for="emailCc">CC </label>
                                <input type="email" name="emailCc" id="emailCc" class="form-control" placeholder="Mail CC">
                            </div>
 
                            <div class="form-group">
                                <label for="emailBcc">BCC </label>
                                <input type="email" name="emailBcc" id="emailBcc" class="form-control" placeholder="Mail BCC">
                            </div>
 
                            <div class="form-group">
                                <label for="emailSubject">Subject </label>
                                <input type="text" name="emailSubject" id="emailSubject" class="form-control" placeholder="Mail Subject">
                            </div>
 
                            <div class="form-group">
                                <label for="emailBody">Message </label>
                                <textarea name="emailBody" id="emailBody" class="form-control" placeholder="Mail Body"></textarea>
                            </div>
 
                            <div class="form-group">
                                <label for="emailAttachments">Attachment(s) </label>
                                <input type="file" name="emailAttachments[]" multiple="multiple" id="emailAttachments" class="form-control">
                            </div>
                        </div>
 
                        <div class="card-footer">
                            <button type="submit" class="btn btn-success">Send Email </button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
      </div>
      
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
  </body>
</html>

Данный код создает простейшую форму следующего вида:

В данной форме необходимо заполнить поля Email To (Получатель), CC (Копия), BCC (Скрытая Копия), Subject (Заголовок), Message (Сообщение) и прикрепить вложения в Attachment(s). После чего отправить данные нажав на кнопку Send Email. В ответ придет сообщение об успешной отправке письма.

Если для отправки писем использовать Gmail SMTP, прежде всего нужно создать пароль приложения для вашего аккаунта Gmail.

Настройка отправки писем через Gmail SMTP сервер

Чтобы использовать Gmail SMTP с библиотекой PHPMailer Laravel, нужно изменить некоторые настройки в аккаунте Google. Выполните следующие шаги:

Следующая инструкция настройки Google аккаунта для взаимодействия с SMTP сервером отличается от интструкции оригинальной статьи в связи с тем, что 30 мая 2022 года Google изменили требования безопасности.

  • Переходим на страницу вашего Аккаунта Google.

  • Затем переходим на страницу Безопасность и пролистываем вниз до секции Вход в аккаунт Google.

  • Убеждаемся, что включена Двухэтапная аутентификация. Если выключена - включаем.

Секция Вход в аккаунт Google
Секция Вход в аккаунт Google
  • Затем в этой же секции переходим в Пароли Приложений. В выпадающем списке Приложение выбираем Другое, затем вводим название приложения, например, Laravel Application и нажимаем кнопку Создать.

Создание пароля приложения
Создание пароля приложения
  • Копируем пароль из появившегося окна подтверждения создания пароля приложения и нажимаем кнопку Готово.

Окно с паролем приложения
Окно с паролем приложения

Теперь у нас есть все данные для использования Gmail SMTP для отправки писем из приложения Laravel.

Изменяем email и пароль в соответствии с учетными данными Gmail в следующей части кода контроллера PHPMailerController.php.

$mail->isSMTP(); 
$mail->Host     = 'smtp.gmail.com'; 
$mail->SMTPAuth = true; 
$mail->Username = 'sender@gmail.com'; 
$mail->Password = '******'; 
$mail->SMTPSecure = 'tls'; 
$mail->Port     = 587;

Все готово для отправки писем через Gmail SMTP сервер в Laravel.

Заключение

В данной статье был рассмотрен алгоритм отправки писем с вложениями из приложении Laravel. Вы можете расширять функционал в соответствии с вашими запросами. Надеюсь данный туториал был полезен для вашего проекта. Продолжайте учиться!

Комментарии (5)


  1. FanatPHP
    17.10.2022 10:05
    +6

    У меня к вам два вопроса.


    1. Почему вы решили переводить именно эту статью? Учитывая, что первое же предложение в статье, "По умолчанию Laravel предлагает отправлять электронную почту через почтовый API на базе библиотеки SwiftMailer" является неверным. Если мы откроем документацию на библиотеку SwiftMailer, то увидим, что её вообще никто не предлагает использовать, поскольку её поддержка уже закончилась. И если мы откроем документацию на Laravel, то увидим, что у него есть свой собственный компонент Mail, который под капотом использует совсем другую библиотеку, Symfony Mailer. И возникает вопрос — а в чем смысл отказываться от рекомендованного пакета?
    2. Зачем вы в принципе решили заняться переводами? Вы уверены, что для фразы
      • "Most of the developers always recommended using an SMTP server to send an email from a script" адекватным переводом является
      • "отправлять письма [...] через SMTP серверы, являющиеся наиболее рекомендованными разработчиками" а не
      • Рекомендованным способом отправки писем из скриптов является использование SMTP сервера?


    1. Lyoulka Автор
      17.10.2022 10:24

      У меня к вам два ответа.

      1. Да, Вы правы о библиотетке SwiftMailer. В Laravel 9 действительно ее не используют, а в данной статье речь идет о Laravel 8, что конечно же следует указать.

      2. Стилистика написания статей и переводов достаточно сильно зависит от личности автора и полученного им ранее опыта в целом. Главное чтобы суть была передана верно, общее представление о вопросе не икажено и текст легко читался.

      Спасибо Вам за внимание и проявленный интерес к переводу. Я учту Ваши замечания и буду становиться лучше!)


      1. dopusteam
        17.10.2022 14:17
        +2

        отправлять письма [...] через SMTP серверы, являющиеся наиболее рекомендованными разработчиками

        Так это стилистика такая, а я думал несогласованное предложение


  1. Encoders
    18.10.2022 21:59

    В статье опечатка в слове username. У вас используется sername


    1. Lyoulka Автор
      18.10.2022 22:01

      Спасибо, поправила. Вы очень внимательны!)