Создать форму обратной связи
С помощью форм обратной связи на сайте можно организовать сбор отзывов от посетителей или приём заказов на услуги или товары.
Разберём пример HTML-страницы и облачной функции для отправки содержимого формы обратной связи на электронную почту:
- создание страницы с формой обратной связи;
- добавление защиты от спама с помощью reCAPTCHA.
Простая форма обратной связи
В этом примере сделаем форму, в которой спросим у пользователя его имя, телефон и обратную связь, которой он хотел бы поделиться: проблемой или идеей для сайта.
HTML внешнего вида формы обратной связи будет выглядеть так:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Us Form Example</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="content container pb-5">
<div class="row justify-content-md-center mt-5 pl-5">
<div class="col-8 mb-3">
<form class="needs-validation" id="mainForm">
<div class="form-group">
<label for="name_field">Name</label>
<input name="name" type="text" class="form-control" id="name_field"
value="Mark" required>
</div>
<div class="form-group">
<label for="phone_field">Phone</label>
<input name="phone" type="text" class="form-control" id="phone_field"
placeholder="+9 999 999999" value="+7 999 888777" required>
</div>
<div class="form-group">
<label for="desc_field">Description</label>
<textarea class="form-control" name="desc" id="desc_field" rows="3"></textarea>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
jQuery(function() {
$('#mainForm').on('submit', function(e) {
e.preventDefault();
$.ajax({
url: '<Место для ссылки на вашу облачную функцию>',
type: 'POST',
cache: false,
data: $(e.target).serialize()
}).done(function() {
alert('Done.');
}).fail(function() {
alert('Something went wrong.');
});
});
});
</script>
</body>
</html>
Приведённый код есть в нашем github-репозитории.
В коде по событию «submit» отправляется AJAX POST-запрос в облачную функцию с содержимым веб-формы. Для этого подключена jQuery, хотя вместо неё может быть другая реализация отправки POST-запроса. Чтобы форма выглядела красиво, использован Bootstrap4, но оформление может быть любым.
Перейдём к облачной функции, которая будет отвечать за обработку полученных данных.
Содержимое формы можно сохранять в СУБД, в Файловое Хранилище, отправлять на электронную почту, в Telegram, в Slack, в свою CRM-систему и так далее — вариантов много. Чтобы решить задачу наиболее общим способом, на каждое обращение будет реализована отправка письма на указанную в настройках функции электронную почту.
Код такой функции будет выглядеть так:
import os
import json
import smtplib
EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.yandex.ru')
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 587))
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_TO = os.environ.get('EMAIL_TO')
def main(**kwargs):
text = json.dumps(kwargs, indent=2, ensure_ascii=False)
print("Received: %s" % text)
server = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
server.ehlo()
server.starttls()
server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
message = "\r\n".join([
f"From: {EMAIL_HOST_USER}",
f"To: {EMAIL_TO}",
"Subject: Serverless Form",
"",
str(text)
])
server.set_debuglevel(1)
server.sendmail(EMAIL_HOST_USER, EMAIL_TO, message)
server.quit()
return "Email was sent"
Приведённый код доступен в нашем github-репозитории.
Код превращает все полученные аргументы в форматированный JSON. Подключается к SMTP-серверу и отправляет письмо в виде текста.
Здесь нужно задать некоторые настройки в переменных окружения, в том числе для подключения к SMTP-серверу, например mail.google.com или mail.yandex.ru.
В итоге есть HTML-форма, которая шлёт AJAX запрос в облачную функцию. При этом URL облачной функции «спрятан» внутри Javascript-кода намеренно, чтобы тривиальные crawler-боты не могли слать спам через эту форму, обнаружив в ней атрибут action.
Форма обратной связи с CAPTCHA
Чтобы отсеивать любых ботов, создадим форму обратной связи с CAPTCHA.
Чтобы добавить CAPTCHA на форму, воспользуемся сервисом reCAPTCHA v3.
Для этого нужно:
- Создать ключ в сервисе google.com/recaptcha.
- Переделать HTML из предыдущей главы в следующий:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Contact Us Form Example</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="content container pb-5">
<div class="row justify-content-md-center mt-5 pl-5">
<div class="col-8 mb-3">
<form class="needs-validation" id="mainForm">
<div class="form-group">
<label for="name_field">Name</label>
<input name="name" type="text" class="form-control" id="name_field"
value="Mark" required>
</div>
<div class="form-group">
<label for="phone_field">Phone</label>
<input name="phone" type="text" class="form-control" id="phone_field"
placeholder="+9 999 999999" value="+7 999 888777" required>
</div>
<div class="form-group">
<label for="desc_field">Description</label>
<textarea class="form-control" name="desc" id="desc_field" rows="3"></textarea>
</div>
<button class="btn btn-primary g-recaptcha"
data-sitekey="<Место для SITE KEY из reCAPTCHA>"
data-callback='onFeedbackFormSubmit'
data-action='submit'>Submit</button>
</form>
</div>
</div>
</div>
<script src="https://www.google.com/recaptcha/api.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
function onFeedbackFormSubmit() {
$.ajax({
url: '<Место для ссылки на вашу облачную функцию>',
type: 'POST',
cache: false,
data: $('#mainForm').serialize()
}).done(function() {
alert('Done.');
}).fail(function() {
alert('Something went wrong.');
});
}
</script>
</body>
</html>
Приведённый код доступен в нашем github-репозитории.
Таким способом можно защитить вызов облачной функции от crawler-ботов.
Для полной защиты нужно провалидировать результат проверки reCAPTCHA со стороны сервера. Это можно сделать так:
import os
import json
import smtplib
from urllib import request, parse
EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.yandex.ru')
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 587))
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_TO = os.environ.get('EMAIL_TO')
RECAPTCHA_SECRET_KEY = os.environ.get('RECAPTCHA_SECRET_KEY')
def is_captcha_challenge_succeed(response_token):
data = parse.urlencode({
'secret': RECAPTCHA_SECRET_KEY,
'response': response_token,
}).encode()
req = request.Request('https://www.google.com/recaptcha/api/siteverify', data=data)
resp_data = json.load(request.urlopen(req))
return resp_data.get('success') or False
def format_email(**kwargs):
return json.dumps(kwargs, indent=2, ensure_ascii=False)
def send_email(text):
server = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
server.ehlo()
server.starttls()
server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
message = "\r\n".join([
f"From: {EMAIL_HOST_USER}",
f"To: {EMAIL_TO}",
"Subject: Serverless Form",
"",
str(text)
])
server.set_debuglevel(1)
server.sendmail(EMAIL_HOST_USER, EMAIL_TO, message)
server.quit()
def main(**kwargs):
if is_captcha_challenge_succeed(kwargs.pop('g-recaptcha-response')):
text = format_email(**kwargs)
print(f'Sending """{text}"""')
send_email(text)
return "Email was sent"
return "CAPTCHA challenge failed"
Приведённый код доступен в нашем github-репозитории.
Реализована форма обратной связи и обеспечена полноценная защита от спам-ботов.