В заключительной статье мы сделаем отправку формы на почту. Важно, что отправляться данная форма будет без перезагрузки страницы (асинхронно). После отправки формы пользователь получит уведомление, что данные отправлены, либо сообщение со статусом ошибки.

Также в конце бонусом покажу, как сделать простую разметку для письма.

Исходники их предыдущих уроков

В первом уроке делали разметку для формы обратной связи, во втором — проверяли поля на правильность ввода (валидация). Вы можете пройти эти уроки, либо скачать исходники из последнего урока по ссылке на GitHub.

Подключение и настройка PHPMailer

PHPMailer — это довольно старая (создана в 2001 г.) библиотека для отправки электронных писем. Не смотря на это — популярна на сегодняшний день. Данная библиотека имеет ряд преимуществ по сравнению со стандартной функцией языка PHP — mail().

  1. Поддерживает принцип объектно-ориентированного программирования
  2. Встроенная аутентификация через TSL, SSL
  3. Поддерживает протокол SMTP, который могут использовать аутентифицированные пользователи
  4. Отображает сообщения об ошибках на 40 языках

Скачать PHPMailer можно по ссылке на GitHub. Архив распаковываем в папке с вашим проектом.

После создаем новый файл send_mail.php — скрипт для отправки сообщений. Внутри него подключаем библиотеку PHPMailer. Вставляем код ниже. Важно, чтобы файлы библиотеки находились в папке PHPMailer.

<?php

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

    require "PHPMailer/src/Exception.php";
    require "PHPMailer/src/PHPMailer.php";

Далее создадим объект mail для работы с почтой и считаем поля формы с файла index.html. Передаем данные методом POST.

$mail = new PHPMailer(true); /* Создаем объект MAIL */
$mail->CharSet = "UTF-8"; /* Задаем кодировку UTF-8 */
$mail->IsHTML(true); /* Разрешаем работу с HTML */

$name = $_POST["name"]; /* Принимаем имя пользователя с формы .. */
$email = $_POST["email"]; /* Почту */
$phone = $_POST["phone"]; /* Телефон */
$message = $_POST["message"]; /* Сообщение с формы */

Подготавливаем письмо к отправке

В скрипте send_mail.php мы получили данные с формы, теперь их необходимо подготовить. Создадим новый файл template_mail.html — HTML-разметку для данных из формы.

<html>
  <body>
    <h3>Данные с формы обратной связи</h3>
    <p>Имя: %name%</p>
    <p>Email: %email%</p>
    <p>Телефон: %phone%</p>
    <p>Сообщение: %message%</p>
  </body>
</html>

Вместо %name% будет вставляться имя пользователя, отправляющего письмо. И так далее. Вы можете создать ту разметку, которая вам нужна.

Чтобы заменить данные в разметке, в файле send_mail.php пропишем следующее:

$email_template = "template_mail.html"; // Считываем файл разметки
$body = file_get_contents($email_template); // Сохраняем данные в $body
$body = str_replace('%name%', $name, $body); // Заменяем строку %name% на имя
$body = str_replace('%email%', $email, $body); // строку %email% на почту
$body = str_replace('%phone%', $phone, $body); // строку %phone% на телефон
$body = str_replace('%message%', $message, $body); // строку %message% на сообщение

Отправляем письмо (пока с перезагрузкой)

Итак теперь все готово, чтобы отправить наше письмо на почту. Здесь мы задаем адрес email (их может быть несколько), тему письма. В конце возвращаем ответ в формате JSON. Это нужно, чтобы показать пользователю, что сообщение успешно отправлено.

$mail->addAddress("your-name@email.com"); /* Здесь введите Email, куда отправлять */
$mail->setFrom($email);
$mail->Subject = "[Заявка с формы]"; /* Тема письма */
$mail->MsgHTML($body);

/* Проверяем отправлено ли сообщение */
if (!$mail->send()) {
  $message = "Ошибка отправки";
} else {
  $message = "Данные отправлены!";
}

/* Возвращаем ответ */	
$response = ["message" => $message];

/* Ответ в формате JSON */
header('Content-type: application/json');
echo json_encode($response);

?>

Отправляем данные без перезагрузки страницы

Теперь перейдем к самому главному, отправим данные на почту без перезагрузки страницы. Отмечу, что все что мы делали до — у вас должно работать.

Подготовка скрипта из прошлого урока

Чтобы сильно не усложнять приведу подготовленный JS-код из предыдущего урока (он хранится в файле app.js).

const form = document.forms["form"];
const formArr = Array.from(form);
const validFormArr = [];
const button = form.elements["button"];

formArr.forEach((el) => {
  if (el.hasAttribute("data-reg")) {
    el.setAttribute("is-valid", "0");
    validFormArr.push(el);
  }
});

form.addEventListener("input", inputHandler);
form.addEventListener("submit", formCheck); // обработка кнопки "Отправить"

function inputHandler({ target }) {
  if (target.hasAttribute("data-reg")) {
    inputCheck(target);
  }
}

function inputCheck(el) {
  const inputValue = el.value;
  const inputReg = el.getAttribute("data-reg");
  const reg = new RegExp(inputReg);
  if (reg.test(inputValue)) {
    el.setAttribute("is-valid", "1");
    el.style.border = "2px solid rgb(0, 196, 0)";
  } else {
    el.setAttribute("is-valid", "0");
    el.style.border = "2px solid rgb(255, 0, 0)";
  }
}

// Здесь проверяем, можно ли отправить форму
function formCheck(e) {
  e.preventDefault(); // блокируем input
  const allValid = []; // создаем массив валидных значений
  validFormArr.forEach((el) => {
    allValid.push(el.getAttribute("is-valid")); // проверяем каждое поле
  });
  const isAllValid = allValid.reduce((acc, current) => {
    // проверяем, чтобы все было правильно
    return acc && current;
  });
  if (!Boolean(Number(isAllValid))) {
    alert("Заполните поля правильно!"); // если не правильно - сообщение пользователю
    return;
  }
  formSubmit(); // если правильно - отправляем данные
}

Самое основное начинается с нажатии на кнопку «Отправить», после этого вызывается функция formCheck, которая (как понятно из названия) проверяет форму на корректность заполненных данных. Сначала мы формируем массив валидных значений, он выглядит примерно так allValid = [0, 1, 1, 0], где 0 — поле заполнено неверно, 1 — поле заполнено верно.

После чего мы сводим весь массив allValid к единому значений isAllValid. Если в массиве allValid все единички, тогда isAllValue = true, в противном случае проверка не пройдена (тогда будет сообщение пользователю). Если проверка пройдена вызываем по цепочке функцию formSubmit.  

Отправка данных на почту

Теперь, когда проверка пройдена, можем отправить данные на почту без перезагрузки страницы. В этом нам поможем асинхронная функция formSubmit

async function formSubmit() {
  const data = serializeForm(form); // получаем данные формы
  const response = await sendData(data); // отправляем данные на почту
  if (response.ok) {
    let result = await response.json(); // если ответ OK отвечает пользователю
    alert(result.message); // .. что данные отправлены
    formReset(); // сбрасываем поля формы
  } else {
    alert("Код ошибки: " + response.status); // если not OK - показываем код ошибки
  }
}

function serializeForm(formNode) {
  // формируем данные формы
  return new FormData(form);
}

async function sendData(data) {
  return await fetch("send_mail.php", {
    // отправляем в скрипт send_mail.php
    method: "POST", // методом POST
    body: data,
  });
}

function formReset() {
  // сброс полей формы
  form.reset();
  validFormArr.forEach((el) => {
    el.setAttribute("is-valid", 0);
    el.style.border = "none";
  });
}

В начале собираем данные с формы с помощью функции serializeForm. Далее эти данные передаем в скрипт send_mail.php функцией sendData. PHP-скрипт сам занимается отправкой сообщения на почту. А мы тем временем ожидаем ответа от PHP-скрипта (специально указали await перед sendData). В этом собственно и заключается асинхронность.  Как только ответ получен, то мы его проверяем: если все ОК — говорим пользователю, что сообщение отправлено и сбрасываем поля формы. В противном случае показываем код ошибки (с сервера). 

Исходный код на GitHub

Скачать исходный код всей формы со скриптами вы можете по ссылке из моего репозитория на GitHub.

 

21 комментарий

  • Это лучший материал на просторах интернета, который удалось найти по созданию форм на сайте. Спасибо автору и удачи в делах. С меня, однозначно, подписка на канал на YouTube.

  • rasul:

    thanks for the work

  • Новичок-v-IT:

    Какой будет код, если подключать SMTP?

  • Сергей:

    Было бы здорово прикрутить сюда еще форму для отправки файла!

  • Игорь:

    Здравствуйте. Спасибо за статью. Подскажите пожалуйста в чем может быть проблема и как её решить? Вставил ваш код, но письма на почту не приходят, в консоли нашел такую ошибку: https://ru.files.fm/u/4mm4tay86

  • Игорь:

    Здравствуйте. подскажите пожалуйста в чем может быть проблема? Скачал с гитхаба ваш код, 3 и 4 версию, заменил в 26 строке на свой адрес почту ($mail->addAddress(«тут почта»); // Здесь введите Email, куда отправлять), но письма не приходит. при этом форма говорит, что письмо отправлено.

    • Дмитрий:

      Та же самая проблема, пидет, что данные отправлены, а на почте пусто

    • Антон Колесников:

      Добрый день, посмотрите в папке спам, возможно туда письма приходят.

      • Игорь:

        папка спам пуста. а вы запускали код, который разместили на гитхабе? Может перед загрузкой что-то изменили?

  • Игорь:

    Разместил ваш код на хостинге, не приходят письма. Если не сложно, посмотрите пожалуйста код https://portfolio.barklay-studio.ru/

  • гость:

    выдаёт ошибку 500 что делать

  • Наталья:

    Здравствуйте у меня не работает кнопка

  • Наталья:

    Здравствуйте у меня не работает кнопка

  • Вадим:

    А можете пожалуйста показать как из корзины отправлять товары на почту (корзина, которую вы делали с телефонами )

  • Игорь:

    Здравствуйте! Залил на Vercel, но почему-то не работает. Выдает 405 ошибку.

  • Андрей:

    с корзины товар на почту не получается отправить, продолжение напишите пожалуйста))

  • Руслан:

    Доброго времени суток! Мне понравился ваш код формы обратной связи. Но у меня на почту приходит: имя: %name%; тел: % phone%; почта:%email%. Что не так я делаю? Помогите разобратся.