Документация / listmonk

Рассылки из listmonk через SMTP

listmonk — менеджер рассылок и списков подписчиков, который устанавливается на свой сервер. Он хранит базу и отправляет кампании, а доставку поручает SMTP-серверам, которые вы укажете: держит к каждому пул соединений и сам ограничивает скорость. Поэтому важны не только хост и пароль, но и пул, темп, отказы и отписки. Ниже — подключение к fmailer.

ℹ
Логин и пароль можно получить на странице токенов домена.

Параметры подключения

ПараметрЗначение
SMTP-хостsmtp.fmailer.ru
Порт587
ШифрованиеSTARTTLS (соединение переводится в TLS до авторизации)
ЛогинЛогин токена вашего домена
ПарольПароль этого токена — показывается один раз, при создании
ℹ
Каждый режим доступен и на высоком порту: 8465 (SSL/TLS), 8587 (STARTTLS) и 8025 (без шифрования). Многие хостинги и облака блокируют исходящие 25, 465 и 587 — если соединение обрывается по таймауту, используйте соответствующий высокий порт.

Шаг 1 — добавьте SMTP-сервер

Откройте Настройки → SMTP и отредактируйте существующий блок или добавьте новый:

ПолеЗначение
ВключеноДа
Хостsmtp.fmailer.ru
Порт587
Протокол аутентификацииPLAIN
Имя пользователяЛогин токена вашего домена
ПарольПароль этого токена
TLSSTARTTLS (SSL/TLS — для порта 465)
Пропустить проверку TLSВыкл
Имя хоста HELOПо желанию — имя сервера, где работает listmonk
⚠
Релей авторизует через AUTH PLAIN и не предлагает LOGIN. С вариантом LOGIN listmonk не пройдёт авторизацию, даже если логин и пароль верны.

Адрес отправителя кампании — и адрес по умолчанию в разделе Настройки → Общие — должен быть на подтверждённом домене, например news@mail.example.ru.

Шаг 2 — пул соединений и таймауты

НастройкаПо умолчаниюРекомендация
Макс. соединений1010 или меньше — лимит тарифа больше соединений не поднимут
Повторные попытки2Оставить: повтор идёт через другое соединение из пула
Тайм-аут простоя15sОставить: простаивающее соединение закрывается и уходит из пула
Тайм-аут ожидания5sОставить

Нажмите «Сохранить», затем «Проверить соединение» у блока — listmonk отправит тестовое письмо на указанный адрес.

Шаг 3 — ограничьте скорость

Часовой лимит тарифа проверяет релей: сверх него каждое письмо получает 550 hourly limit exceeded, а после «Максимального порога ошибок» listmonk ставит кампанию на паузу. Лучше, чтобы listmonk сдерживал себя сам, — в разделе Настройки → Производительность:

  • «Включить ограничение скользящего окна», «Длительность» 1h, «Макс. сообщений» — чуть меньше часового лимита тарифа.
  • «Параллелизм» × «Скорость отправки сообщений» — потолок писем в секунду. После настройки окна значения по умолчанию можно не трогать.

Прогрев нового домена устроен иначе: он ничего не отклоняет, а письма сверх потолка доставляет позже. Подробнее — на странице лимитов отправки.

Отписка

Если в разделе Настройки → Конфиденциальность включён заголовок List-Unsubscribe, listmonk добавляет в каждое письмо кампании пару заголовков для отписки в одно нажатие. Когда мы относим письмо к массовым, релей заменяет эту пару своей: отписка попадает в список отписавшихся домена, и следующие письма на этот адрес мы не доставляем. В listmonk подписчик при этом остаётся активным — кого обновить, подскажет вебхук unsubscribed. Ссылка отписки в самом шаблоне по-прежнему ведёт в listmonk.

Шаг 4 — настройте обработку отказов

Включите Настройки → Отказы → «Включить обработку отказов», задайте действия (жёсткий отказ: количество 1, действие «Чёрный список») и подключите один или оба источника:

  • Почтовый ящик для отказов (POP3). Письма об отказах приходят на адрес конверта — адрес отправителя кампании или Return-Path из пользовательских заголовков SMTP-блока. Он должен быть на подтверждённом домене, а return path домена в панели — пустым, иначе он заменит адрес listmonk.
  • Вебхуки для отказов. Отказ, полученный нашими серверами при доставке, письмом не возвращается — он приходит вебхуком bounced. Включите вебхуки для отказов, создайте API-пользователя с ролью, в которой есть право webhooks:post_bounce, и передавайте события:
bounce_bridge.pypython
# Передаёт события bounced и complained в API отказов listmonk.
import hashlib, hmac, os, time
import requests
from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["WEBHOOK_SECRET"]           # секрет эндпоинта вебхуков
LISTMONK = "https://lists.example.ru"
API_AUTH = ("bounce-bot", os.environ["LISTMONK_TOKEN"])  # API-пользователь listmonk
TYPES = {"bounced": "hard", "complained": "complaint"}

@app.post("/hooks/delivery")
def delivery():
    raw = request.get_data(as_text=True)
    ts = request.headers["X-Webhook-Timestamp"]
    sig = request.headers["X-Webhook-Signature"]
    expected = hmac.new(SECRET.encode(), f"{ts}.{raw}".encode(), hashlib.sha256).hexdigest()
    if abs(time.time() - int(ts)) > 300 or not hmac.compare_digest(expected, sig):
        abort(400)

    event = request.get_json()
    if event["event"] in TYPES:
        requests.post(f"{LISTMONK}/webhooks/bounce", auth=API_AUTH, timeout=10, json={
            "email": event["email"],
            "source": "relay",
            "type": TYPES[event["event"]],
        }).raise_for_status()
    return "", 204

Разбор ошибок

СимптомПричина и решение
Ошибка авторизации при верном паролеВыбран протокол LOGIN или None — поставьте PLAIN.
Проверка соединения зависает Исходящий порт заблокирован — используйте 8587 со STARTTLS или 8465 с SSL/TLS.
550 from must be equal to … Адрес отправителя или Return-Path из заголовков не на подтверждённом домене.
Кампания на паузе, 550 hourly limit exceededВключите ограничение скользящего окна и возобновите кампанию.
Вебхук отказов отвечает 404Не включены вебхуки в разделе Настройки → Отказы.
Письма в спаме Отправитель не на подтверждённом домене либо в базе есть неподтверждённые или давно неактивные адреса.

Частые вопросы

Какой протокол аутентификации выбрать в listmonk?

PLAIN. Релей принимает AUTH PLAIN по зашифрованному соединению и не предлагает LOGIN, поэтому с вариантом LOGIN listmonk не авторизуется даже с верным паролем. Новый SMTP-блок создаётся с вариантом None — тогда логин и пароль не отправляются вовсе.

Сколько ставить в «Макс. соединений»?

Начните со значения по умолчанию — 10 — или меньше. Дополнительные соединения помогают, только если воркеры listmonk ждут сеть. Часовой лимит тарифа они не поднимают, и рассылка быстрее лимита просто раньше упирается в отказ.

Как не превысить часовой лимит тарифа?

Настройки → Производительность → «Включить ограничение скользящего окна»: длительность 1h, «Макс. сообщений» — чуть меньше часового лимита тарифа. Тогда listmonk придерживает письма до конца окна, а не получает на них 550.

Добавляет ли listmonk заголовок List-Unsubscribe?

Да, если в разделе Настройки → Конфиденциальность включён заголовок List-Unsubscribe: listmonk ставит List-Unsubscribe и List-Unsubscribe-Post для отписки в одно нажатие. В письмах, которые мы относим к массовым, релей заменяет эту пару своей, и отписка записывается у нас, а не в listmonk.

Почему рассылка встала на паузу с ошибками?

listmonk приостанавливает кампанию, когда ошибок становится больше «Максимального порога ошибок» (Настройки → Производительность). С релеем обычная причина — 550 hourly limit exceeded. Включите скользящее окно и возобновите кампанию.

Как listmonk узнаёт об отказах?

Из POP3-ящика, куда приходят письма об отказах, или через свой API вебхуков. Отказ, полученный нашими серверами при доставке, письмом не возвращается, поэтому такие отказы ловит только мост на вебхуках — пример ниже.

Что дальше