В этом руководстве — как отправлять письма через Haskimail из приложений на Django и Flask. Есть два способа:
- SMTP — самый простой для Django: используется встроенный почтовый механизм, код почти не меняется.
- HTTP API — даёт больше возможностей: каналы, теги, метаданные, шаблоны, пакетная отправка. Подходит и для Django, и для Flask.
Для Python есть и официальная библиотека (pip install haskimail), но в примерах ниже используется только requests, чтобы было видно, что именно отправляется в API.
Что нужно подготовить
- Подтверждённый адрес отправителя или домен. Адрес в поле «От кого» должен быть подтверждён в разделе «Домены и отправители». Пока аккаунт на модерации, письма можно отправлять только на адреса подтверждённых доменов.
- Данные для подключения:
- для SMTP — SMTP-реквизиты канала (логин и пароль) из настроек канала отправки;
- для API — серверный API-ключ: SMTP-серверы → ваш сервер → API-ключи.
- Python 3.10 или новее.
Храните ключи и пароли в переменных окружения или менеджере секретов, а не в коде и не в репозитории.
Django через SMTP
В settings.py:
import os
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.haskimail.ru"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ["HASKIMAIL_SMTP_LOGIN"]
EMAIL_HOST_PASSWORD = os.environ["HASKIMAIL_SMTP_PASSWORD"]
DEFAULT_FROM_EMAIL = "Магазин <support@example.ru>"
Если хотите использовать порт 465, замените EMAIL_PORT = 465 и EMAIL_USE_TLS = True на EMAIL_USE_SSL = True.
Теперь письма отправляются обычными средствами Django:
from django.core.mail import send_mail
send_mail(
subject="Заказ оформлен",
message="Спасибо за заказ!",
from_email=None, # будет использован DEFAULT_FROM_EMAIL
recipient_list=["customer@example.com"],
fail_silently=False,
)
Письмо с HTML-версией:
from django.core.mail import EmailMultiAlternatives
msg = EmailMultiAlternatives(
subject="Заказ оформлен",
body="Спасибо за заказ! Детали — в личном кабинете.",
to=["customer@example.com"],
)
msg.attach_alternative("<h1>Спасибо за заказ</h1>", "text/html")
msg.send()
Письма уходят через канал, чьи SMTP-реквизиты вы указали. Для транзакционных писем и рассылок используйте разные каналы.
Отправка через HTTP API (Django и Flask)
Функция для отправки одного письма:
import os
import requests
HASKIMAIL_URL = "https://api.haskimail.ru/email"
def send_via_haskimail(*, from_addr, to, subject, text, html=None, stream=None):
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"X-Haskimail-Server-Token": os.environ["HASKIMAIL_SERVER_TOKEN"],
}
body = {"From": from_addr, "To": to, "Subject": subject, "TextBody": text}
if html:
body["HtmlBody"] = html
if stream:
body["MessageStream"] = stream # ID канала; без него — транзакционный канал
resp = requests.post(HASKIMAIL_URL, headers=headers, json=body, timeout=30)
data = resp.json()
if resp.status_code != 200 or data.get("ErrorCode") != 0:
raise RuntimeError(f"Haskimail: {data.get('ErrorCode')} {data.get('Message')}")
return data["MessageID"]
Функция возвращает MessageID письма — сохраните его, чтобы связывать письмо с событиями доставки, открытий и кликов. Если письмо не принято, API отвечает HTTP 422 с кодом ошибки — что означают коды, рассказываем в статье «Ответ API при отправке письма и коды ошибок».
Вызывайте функцию из view, фоновой задачи (Celery, RQ) или скрипта:
send_via_haskimail(
from_addr="Магазин <support@example.ru>",
to="customer@example.com",
subject="Заказ оформлен",
text="Спасибо за заказ!",
html="<p>Спасибо за заказ!</p>",
)
Пример для Flask
from flask import Flask
app = Flask(__name__)
@app.post("/orders/<int:order_id>/confirm")
def confirm_order(order_id):
# ... ваша логика оформления заказа ...
send_via_haskimail(
from_addr="Магазин <support@example.ru>",
to="customer@example.com",
subject=f"Заказ №{order_id} оформлен",
text=f"Спасибо! Ваш заказ №{order_id} принят.",
)
return {"status": "ok"}
Важно: не создавайте в приложении публичный адрес, который отправляет письма на любой адрес из запроса. Через такой адрес кто угодно сможет рассылать спам от вашего имени. Отправляйте письма только в ответ на конкретные действия пользователя, а в рабочей среде не запускайте Flask с debug=True.
Проверка без реальной отправки
Чтобы проверить код без отправки писем, передайте вместо серверного ключа тестовый — HASKIMAIL_API_TEST. API проверит запрос и вернёт ответ в обычном формате, но письмо никуда не уйдёт. Чтобы проверить отправку целиком, используйте сервер «Песочница».
Частые ошибки
ErrorCode 10 «Неверный API-ключ»
- Используется не серверный ключ, а ключ аккаунта или ключ другого сервера.
- В переменной окружения лишние пробелы, кавычки или перенос строки.
- Ключ передан в заголовке
Authorization: Bearer— нуженX-Haskimail-Server-Token.
SMTP: ошибка авторизации
- Проверьте, что указаны SMTP-реквизиты канала, а не API-ключ.
- Проверьте, что для сервера включена отправка по SMTP.
SMTP: не удаётся подключиться
- Провайдер может блокировать порт. Попробуйте 587 или 2525 — см. «Что делать, если порт 25 заблокирован».
Письмо отправлено, но не дошло
- Найдите письмо в логе активности канала и посмотрите его статус — см. «Почему получатель не получил моё письмо».