Python Django: контактная форма с автоматической отправкой Email

Адрес контактной электронной почты часто указан в самом нижнем колонтитуле на сайте. Пользователь должен не только отыскать адрес электронной почты, но еще и самостоятельно отправить письмо. Хотя такой способ организации обратной связи ни в коем случае нельзя назвать плохим, он все-таки требует от пользователя гораздо больше усилий, чем необходимый минимум.

Клиенту нужно угождать, ценить его время  —  так давайте попробуем облегчить процесс отправки электронного письма! Нам в этом поможет контактная форма, автоматически отправляющая письмо в техподдержку сайта. Хотя решение задачи на первый взгляд может показаться сложным, почти весь функционал успешно создается с помощью фреймворка Python Django.

Статья даст ответы на следующие вопросы, волнующие каждого начинающего Python Django веб-разработчика.

  • Как создать поля контактной формы Django?
  • Как добавить форму в HTML шаблон?
  • Как добавить бэкенд электронной почты Django?

1. Создание контактной формы в forms.py

Путь к файлу: env > mysite > main > forms.py

from django import forms

class ContactForm(forms.Form):
    first_name = forms.CharField(max_length=50)
    last_name = forms.CharField(max_length=50)
    email_address = forms.EmailField(max_length=150)
    message = forms.CharField(widget=forms.Textarea,
                              max_length=2000)

Чтобы создать контактную форму, необходимо в файле forms.py унаследовать от базового класса forms.Form класс контактной формы. Она будет называться ContactForm и содержать поля для запроса основной контактной информации о клиенте перед отправкой сообщения в техподдержку. При создании Django-приложения файл forms.py не создаётся автоматически, поэтому создайте его собственноручно в директории приложения main (там, где находится файл models.py).

Внутри класса ContactForm(forms.Form) определите поля first_name и last_name (имя и фамилия), воспользовавшись классом CharField из модуля form  —  так создаются символьные (текстовые) поля. Для каждого из них установите атрибуту max_length значение 50: теперь форма ограничит допустимый ввод в одно поле до 50 символов. Затем добавьте новое поле email_address с помощью класса EmailField из модуля form  —  это специфическое поле, перед отправкой формы автоматически проверяющее соответствие ввода пользователя формату адреса электронной почты. Наконец, добавьте поле message с помощью того же класса CharField, но с виджетом forms.Textarea, указывающим, что данное поле будет отрисовываться в HTML как принимающее длинный текст в стиле абзаца.

Сохраните все изменения в файле forms.py!

2. Создание представления для страницы с формой во views.py

Путь к файлу: env > mysite > main > views.py

from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse

def homepage(request):
    return render(request, "main/home.html")

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            subject = "Пробное сообщение"
            body = {
                'first_name': form.cleaned_data['first_name'],
                'last_name': form.cleaned_data['last_name'],
                'email': form.cleaned_data['email_address'],
                'message': form.cleaned_data['message'],
            }
            message = "\n".join(body.values())
            try:
                send_mail(subject, message, 
                          '[email protected]',
                          ['[email protected]'])
            except BadHeaderError:
                return HttpResponse('Найден некорректный заголовок')
            return redirect("main:homepage")

    form = ContactForm()
    return render(request, "main/contact.html", {'form': form})

Откройте файл views.py, импортируйте в него ряд объектов, которые нам пригодятся.

  1. Функция send_mail (отправка сообщения) и класс BadHeaderError (исключение для перехвата) из модуля django.core.mail.
  2. Функции render (отрисовка страницы на основе шаблона и данных контекста) и redirect (перенаправление браузера на другую страницу) из модуля django.shortcuts.
  3. Класс HttpResponse (ответ на HTTP-запрос к серверу от браузера пользователя) из модуля django.http.
  4. Класс ContactForm из только что созданного нами модуля forms.py.

Далее создайте функцию-представление contact(request) и укажите один блок с условием, которое проверяет соответствие клиентского запроса об отправке формы HTTP-методу POST. Другими словами, если HTTP-запрос от пользователя на отправку контактной формы использует именно метод POST  —  то начинается выполнение следующих строчек кода.

  1. Создайте переменную form = ContactForm(request.POST), ссылающуюся в качестве значения на экземпляр класса, а в качестве аргумента передайте этому классу данные, только что отправленные пользователем к вам на сервер с помощью HTTP-запроса методом POST.
  2. Снова напишите блок условия if form.is_valid(), который будет содержать действия, выполняющиеся только в случае успешной проверки ввода пользователя, ведь в случае некорректности введенных пользователем данных нам не стоит отправлять сообщение в техподдержку.
  3. Приступим к созданию сообщения для отправки на электронную почту. Темой сообщения (переменная subject) будет текст “Пробное сообщение”, а телом сообщения (переменная body)  —  поочередно все поля формы, заполненные правильно. Получить к ним доступ можно с помощью обращения к атрибуту проверенной формы с “чистыми” данными form.cleaned_data[‘form_field’]. Атрибут cleaned_data доступен только внутри блока условия if form.is_valid().
  4. Форматируем текст сообщения. Для этого с помощью выполнения метода \n.join(body.values()) объединим в один текст и разделим символом новой строки все значения ключей словаря body.values(). Получившийся результат сохраняем в переменную message.
  5. Теперь можно отправлять сообщение. Воспользуемся функцией send_mail(subject, message, 'адрес отправителя', 'адрес получателя').
  6. В качестве адресов электронной почты отправителя и получателя устанавливаем [email protected], чтобы текст письма был виден в терминале, так как это удобно для тестирования.
  7. Теперь нужно перехватить ошибку плохого заголовка BadHeaderError, чтобы предотвратить вставку злоумышленниками дополнительных заголовков электронной почты. Если обнаружен “плохой заголовок”, то представление вернет клиенту HttpResponse с текстом “Найден некорректный заголовок”.
  8. Если форма отправлена правильно, реализуем перенаправление клиента на домашнюю страницу приложения с помощью функции redirect('main:homepage'). Если у вашего приложения нет главной страницы, то создайте для неё URL-адрес с названием “homepage” в файле urls.py.
  9. В конце концов, нам необходимо реализовать отправку в браузер пользователя той формы, которую он будет заполнять. Для этого вне любых блоков условий, на самом первом уровне функции, создайте переменную form = ContactForm(). С помощью возврата представлением результата работы метода render(request, “main/contact.html”, {‘form’: form}) предоставьте браузеру пользователя страницу с шаблоном contact.html и контактной формой в качестве контекста для этого шаблона.

3. Создание URL-пути для страницы с формой в urls.py

Путь к файлу: env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"

urlpatterns = [
    path("", views.homepage, name="homepage"),
    path("contact", views.contact, name="contact"),
]

Теперь добавим URL страницы с контактной формой в urls.py нашего приложения. Если же вы используете существующий шаблон с указанным ранее URL, то пропустите этот шаг.

4. Создание шаблона contact.html

Путь к файлу: env > mysite > main > templates > main > contact.html

<!--Contact form-->
<div style="margin:80px">
    <h1>Контакты</h1>
    <h4>Напишите нам, если у вас есть вопросы</h4>
    <p>
        Пожалуйста, напишите свое имя, адрес электронной почты и сообщение.
    </p>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Отправить</button>
    </form>
</div>

Откройте файл contact.html или файл шаблона по вашему выбору и пропишите HTML-тег <form></form> под текстом. Добавьте к этому тегу атрибут method=”POST”, чтобы форма использовала метод POST при отправке данных обратно в функцию-представление contant(request). Внутри элемента формы вложите шаблонный тег Django {%csrf_token%}, чтобы предотвратить подделку формы злоумышленниками. Это очень важная строчка кода, которая позволит вашему Django-проекту безопасно отправлять информацию.

После CSRF-токена обратитесь к полям формы ContactForm, находящимся в контексте шаблона. Чтобы обернуть все поля в теги <p></p>, используйте {{form.as_p}}. Вы также можете получить доступ ко всем полям по отдельности, используя формат {{form.name_of_field}}.

Наконец, добавьте кнопку отправки формы непосредственно перед закрывающим тегом </form>.

5. Добавление Email backend в настройки проекта

Путь к файлу: env > mysite > main > settings.py

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Если включен режим разработчика, то письмо отправляется в CLI (интерфейс командной строки), а не на почтовый ящик.

В нижней части файла settings.py добавьте вышеописанную константу EMAIL_BACKEND, так как именно она устанавливает командную строку/терминал в качестве почтового бэкенда Django для целей тестирования, но со временем стоит заменить настройку почтового бэкенда на реальный сервис отправки электронной почты.

6. Отправка пробного электронного письма в CLI

macOS Terminal/Windows Command Prompt

____________________________________________________________________
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Пробное сообщение
From: [email protected]
To: [email protected]
Date: Wed, 05 Feb 2020 00:04:43 -0000
Message-ID: [123456789@DESKTOP]

Джон
Смит
[email protected]
Привет, хочу задать вопрос...
____________________________________________________________________

Наконец-то в браузере можно заполнить и отправить контактную форму. Перейдите по ссылке http://127.0.0.1:8000/contact. После отправки формы на сервер браузер будет мгновенно перенаправлен на домашнюю страницу приложения main.

Но как же узнать, что электронное письмо отправилось корректно?

Перейдите в командную строку или терминал, и там вы увидите примерно то же самое сообщение, что написано в блоке кода вверху параграфа. Электронные письма можно прочитать прямо в CLI из-за того, что мы настроили почтовый бэкенд Django на вывод в консоль, а не на фактическую отправку письма.

7. Что делать, если ‘django.core.mail.backends.console.EmailBackend’ не работает?

Если бэкенд электронной почты Django в настройках не работает, то выполните следующие шаги.

  1. Проверьте, нет ли орфографических ошибок.
  2. Убедитесь, что значение константы EMAIL_BACKEND является строкой, обрамлённой кавычками.
  3. Если вышеописанное не является причиной ошибки, то перейдите к файлу views.py и убедитесь, что функция send_email и класс BadHeaderError импортированы из django.core.mail, а HttpResponse импортирован из django.http в верхней части файла.
  4. Наконец, убедитесь, что вы создали блоки try и except в функции-представлении contact(request) из файла views.py, иначе данная функция не будет работать должным образом и письмо не будет отправлено.

env > mysite > main > views.py

from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse

def homepage(request):
    return render(request, "main/home.html")

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            subject = "Пробное сообщение"
            body = {
                'first_name': form.cleaned_data['first_name'],
                'last_name': form.cleaned_data['last_name'],
                'email': form.cleaned_data['email_address'],
                'message': form.cleaned_data['message'],
            }
            message = "\n".join(body.values())
            try:
                send_mail(subject, message, 
                          '[email protected]',
                          ['[email protected]'])
            except BadHeaderError:
                return HttpResponse('Найден некорретный заголовок')
            return redirect("main:homepage")

    form = ContactForm()
    return render(request, "main/contact.html", {'form': form})

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Оригинал статьи Ordinary Coders: Build a Django Contact Form with Email Backend

Предыдущая статьяКак находить уязвимости в коде на PHP?
Следующая статьяПостроение бесконечного списка с помощью SwiftUI и Combine