Перейти к основному содержимому

Исходящая почта на бэкенде

Разработчику

Регистрация, сброс пароля, счета, уведомления — email остаётся надёжным каналом, когда push и мессенджеры недоступны. Бэкенд не «рисует письмо в браузере», а формирует сообщение и передаёт его почтовой инфраструктуре.


Цепочка доставки

На практике приложение редко говорит напрямую с MX Gmail: чаще используют транзакционный SMTP (облачный релей) с API или SMTP-auth.


Структура письма (MIME)

Письмо — текст с заголовками (RFC 5322 + MIME):

ЗаголовокНазначение
FromОтправитель (должен быть разрешён SPF/DKIM домена)
To / Cc / BccПолучатели
SubjectТема (кодировка UTF-8 → base64 в заголовке)
Message-IDУникальный идентификатор (полезен для поддержки)
Content-Typetext/plain, text/html, multipart/alternative

Multipart — одно письмо с несколькими частями: plain + HTML + вложения. Клиент выбирает подходящую часть.

Упрощённый каркас multipart/alternative (как формирует библиотека или MTA):

From: Shop <noreply@shop.example>
To: user@example.com
Subject: =?UTF-8?B?0J7Qv9C40YHQutC+0L3RgdC60Lg=?=
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="boundary42"

--boundary42
Content-Type: text/plain; charset=utf-8

Сброс пароля: https://shop.example/reset?token=…

--boundary42
Content-Type: text/html; charset=utf-8

<p>Сброс пароля: <a href="https://shop.example/reset?token=…">перейти</a></p>

--boundary42--

На DNS домена отправителя настраивают SPF (кто может слать от имени домена), DKIM (подпись письма) и DMARC (политика при несовпадении) — без этого транзакционные письма часто попадают в спам.

Кодировки тела:

  • base64 — бинарные вложения, нелатиница в старых клиентах;
  • quoted-printable — текст с редкими не-ASCII символами.

Что реализует бэкенд

  1. Шаблоны — отделение текста от кода (HTML + подстановка переменных).
  2. Очередь — отправка асинхронно: HTTP-запрос не ждёт SMTP 30 секунд.
# После успешной регистрации — не блокировать ответ клиенту
def register_user(email: str, password: str) -> User:
user = create_user(email, password)
queue.enqueue("send_email", template="welcome", user_id=user.id)
return user
  1. Идемпотентность — повтор задачи не должен слать десятое «сбрось пароль»; ключ: userId + template + window.
  2. Логирование — статус queued / sent / bounced, без паролей в логах.
  3. Unsubscribe — для маркетинга обязателен; для транзакционных писем — другие правила.

Типичные ошибки:

  • синхронная отправка в обработчике HTTP → таймауты;
  • нет retry с экспоненциальной паузой при 4xx/5xx релея;
  • From-домен без SPF, DKIM, DMARC → письма в спаме.

Тестирование без риска

СредаПодход
ЛокальноПоднять песочницу SMTP: все письма перехватываются, в веб-UI видно HTML
CIMock SMTP или заглушка API провайдера
StagingОтдельный домен, whitelist получателей

Никогда не гоняйте автотесты на реальные ящики пользователей.

Проверка порта с сервера: openssl s_client -connect smtp.example:587 -starttls smtp (или аналог в терминале).


Безопасность

  • Не вставляйте в HTML неэкранированные пользовательские данные (XSS в почтовике).
  • Ссылки сброса пароля — одноразовые токены с коротким TTL.
  • Rate limit на «отправить письмо» — защита от спама и перебора email.

Подробнее об общей модели: безопасность приложений.


Связанные темы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).