Форма обратного звонка на React + Express + Яндекс SMTP / Отправка форм обратных связей через SMTP
-
Схема работы
React-форма → POST /api/callback → Express → SMTP Яндекса → письмо на почтуReact отправляет
POST-запрос. Express принимает данные и отправляет письмо черезnodemailer. Логин и пароль хранятся только на сервере.
Важно: IMAP ≠ SMTP
- IMAP - для чтения почты.
- SMTP - для отправки писем.
Включенный IMAP в настройках Яндекса не дает возможности отправлять письма. Нужен SMTP + пароль приложения.
Установка
npm install express nodemailer cors dotenv
Переменные окружения
Создайте файл
.envи добавьте его в.gitignore:YANDEX_EMAIL=your@yandex.ru YANDEX_APP_PASSWORD=пароль_приложения PORT=3001Пароль приложения создаётся в Яндекс ID → Безопасность → Пароли приложений → Почта. Основной пароль от аккаунта использовать нельзя.
Модуль отправки
// lib/mailer.js import nodemailer from 'nodemailer'; const transporter = nodemailer.createTransport({ host: 'smtp.yandex.ru', port: 465, secure: true, auth: { user: process.env.YANDEX_EMAIL, pass: process.env.YANDEX_APP_PASSWORD, }, }); export async function sendCallbackEmail({ name, phone, message }) { await transporter.sendMail({ from: `"Сайт" <${process.env.YANDEX_EMAIL}>`, to: process.env.YANDEX_EMAIL, subject: `Обратный звонок: ${name}`, html: ` <p><b>Имя:</b> ${name}</p> <p><b>Телефон:</b> ${phone}</p> <p><b>Сообщение:</b> ${message || 'не указано'}</p> `, }); }
Express-сервер
// server.js import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import { sendCallbackEmail } from './lib/mailer.js'; const app = express(); app.use(cors({ origin: 'http://localhost:3000' })); app.use(express.json()); app.post('/api/callback', async (req, res) => { const { name, phone, message } = req.body; if (!name || !phone) { return res.status(400).json({ error: 'Имя и телефон обязательны' }); } try { await sendCallbackEmail({ name, phone, message }); res.json({ success: true }); } catch (err) { console.error(err); res.status(500).json({ error: 'Ошибка отправки письма' }); } }); app.listen(process.env.PORT, () => { console.log(`Server running on port ${process.env.PORT}`); });
React-форма
// components/CallbackForm.jsx import { useState } from 'react'; const INITIAL = { name: '', phone: '', message: '' }; export function CallbackForm() { const [form, setForm] = useState(INITIAL); const [status, setStatus] = useState('idle'); // idle | loading | success | error const onChange = (e) => setForm((p) => ({ ...p, [e.target.name]: e.target.value })); const onSubmit = async (e) => { e.preventDefault(); setStatus('loading'); try { const res = await fetch('http://localhost:3001/api/callback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form), }); if (!res.ok) throw new Error(); setStatus('success'); setForm(INITIAL); } catch { setStatus('error'); } }; return ( <form onSubmit={onSubmit}> <input name="name" value={form.name} onChange={onChange} placeholder="Имя" required /> <input name="phone" value={form.phone} onChange={onChange} placeholder="Телефон" required /> <textarea name="message" value={form.message} onChange={onChange} placeholder="Сообщение" /> <button type="submit" disabled={status === 'loading'}> {status === 'loading' ? 'Отправка...' : 'Заказать звонок'} </button> {status === 'success' && <p>✅ Заявка отправлена</p>} {status === 'error' && <p>❌ Ошибка. Попробуйте позже</p>} </form> ); }
Структура проекта
project/ ├── server.js ├── lib/ │ └── mailer.js ├── .env ← не коммитить ├── .gitignore └── client/ ← React-приложение └── src/ └── components/ └── CallbackForm.jsx
Запуск
# Сервер node server.js # React (отдельный терминал) npm start
Частые ошибки
Ошибка Причина Решение Invalid loginОсновной пароль вместо пароля приложения Создать пароль приложения в Яндекс ID Connection refusedСервер не запущен или неверный порт Проверить PORTв.envCORS-ошибка Неверный originвcors()Указать адрес React-приложения Письмо не приходит SMTP не разрешён в настройках Яндекса Включить SMTP в настройках почты
Что добавить в продакшене
- Rate limiting -
express-rate-limit, чтобы ограничить спам. - Валидация -
zodилиjoiдля проверки данных на сервере. - Переменные окружения на сервере - не
.envфайл, а переменные хостинга. - HTTPS - обязательно при развёртывании.
Порт использовать для Яндекс SMTP
465(SSL). Можно587сsecure: falseи STARTTLS.Как проверить, что письмо уходит, до подключения React?
Протестировать маршрут через Postman илиcurl:curl -X POST http://localhost:3001/api/callback \ -H "Content-Type: application/json" \ -d '{"name":"Тест","phone":"+79001234567"}' -
Как получить пароль приложения для Яндекс почты
Заходим в настройки почты

Далее проваливаемся в почтовые программы

Видим разрашения доступов

Тыкаем на пароли приложения

Яндекс опять показывает кучу всего не нужного, тыкаем на “Безопасность”

И вот тут наконец-то мы видим наши долгожданные пароли приложений если прокрутить вниз

Далее создаем пароль приложения, кстати важно! Пароль показывается один раз, так что запишите его.

Ну, а кому лень тыкать и понимать где находятся пароли приложения, вот ссылка - https://id.yandex.ru/security/app-passwords по ней сразу перейдете в нужный раздел, только убедитесь что вы залогинены в нужной вам почте.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.