Интеграция форм на сайте

Обновлено: Sep 21, 2026Раздел: Интеграции

Подключите формы подписки на вашем сайте к Mailoo. Каждая корректная отправка создаёт входящее сообщение и обновляет или создаёт запись подписчика. Используйте интеграцию FORM и вызывайте API только с сервера или BFF.

Быстрый старт

  1. Создайте проект и интеграцию Form в панели управления Mailoo (или через MCP create_integration с type=FORM).
  2. Сгенерируйте API-ключ. Для ключей RESTRICTED укажите webhook.form-submission. Агенты также могут настраивать Connection & settings, шаблоны, подписчиков, кампании и сообщения через MCP-инструменты manage_form_* (скоуп form.manage / MCP-токен) --- см. /development/mailoo-mcp{.interpreted-text role="doc"}.
  3. Сохраните ключ и идентификаторы в серверных переменных окружения.
  4. Отправляйте данные формы на ваш собственный маршрут; этот маршрут пересылает их в Mailoo.
  5. Проверьте наличие сообщения и подписчика в панели управления.

:::: important ::: title Important :::

Только на стороне сервера. Браузер не должен содержать X-API-Key. Не размещайте учётные данные Mailoo в клиентском JavaScript. ::::

:::: note ::: title Note :::

Устаревший подход (не рекомендуется): Прямой вызов вебхуков Mailoo из браузера может работать при настроенных CORS и разрешённых источниках, однако при этом API-ключ становится доступен клиенту. Не используйте этот подход для новых интеграций. ::::

Next.js с @mailoo/forms

Для хостов на Next.js App Router предпочтите пакет @mailoo/forms: фабрики BFF-маршрутов того же происхождения, типизированные тела отправки и клиентские хуки. См. website-forms-nextjs-example{.interpreted-text role="doc"}.

Для регистрации или активации идентифицированного пользователя (не анонимная подписка на рассылку) отправляйте события жизненного цикла с вашего сервера --- см. lifecycle-events{.interpreted-text role="doc"}.

Создание интеграции

  1. Перейдите в Панель управления → Проекты → [Ваш проект] → Интеграции.
  2. Создайте новую интеграцию и выберите Form Integration.
  3. Укажите Имя, Статус (Active) и опциональные Разрешённые источники (схема + хост, например https://example.com). Если список пуст, Origin не проверяется. Авторизация осуществляется через API-ключ. BFF, пересылающий заголовок Origin браузера, по-прежнему применяет заполненный список.

Тело запроса

Ваш сервер отправляет JSON в Mailoo:

  • email --- обязательно
  • name --- необязательно
  • subject --- необязательно (значение по умолчанию, например "New subscription")
  • content --- необязательно (значение по умолчанию, например "New subscription from {email}")
  • source, metadata --- необязательно, сохраняются вместе с сообщением

Кампания или шаблон сообщения не требуются для приёма заявок. Входящее сообщение формируется из тела запроса (или значений по умолчанию).

Перенаправление пользователя после успешной отправки --- это ответственность вашего сайта. Mailoo не предоставляет URL для перенаправления.

Эндпоинт API

POST /api/v1/webhooks/forms/{projectUid}/{integrationId}

Заголовки: Content-Type: application/json, X-API-Key (обязательно). Необязательный Origin при использовании списка разрешённых источников.

Пример тела запроса:

{
  "email": "john@example.com",
  "name": "John Doe",
  "source": "https://yoursite.com/newsletter",
  "metadata": {
    "type": "newsletter_subscription"
  }
}

Новый подписчик --- сообщение создано:

{
  "success": true,
  "messageId": "msg_abc123def456",
  "message": "Form submission processed successfully"
}

Уже подписан (тот же e-mail) --- новое сообщение не создаётся; unsubscribedAt сбрасывается при необходимости; ответ не содержит messageId:

{
  "success": true,
  "message": "Already subscribed"
}

Ошибки валидации возвращают поля error и message (например, "Email is required", "Invalid email format").

Серверный пример (Express)

Форма отправляет данные на ваш маршрут. Ваш маршрут вызывает Mailoo:

app.post('/api/subscribe', async (req, res) => {
  const { email, name } = req.body
  if (!email || !email.includes('@')) {
    return res.status(400).json({ error: 'Valid email is required' })
  }

  const response = await fetch(
    `${process.env.MAILOO_API_URL}/api/v1/webhooks/forms/${process.env.PROJECT_UID}/${process.env.INTEGRATION_ID}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': process.env.MAILOO_API_KEY,
        Origin: process.env.WEBSITE_ORIGIN || '',
      },
      body: JSON.stringify({
        email: email.trim(),
        name: name?.trim() || undefined,
        source: req.headers.referer || 'server-side-form',
      }),
    }
  )

  const result = await response.json()
  return res.status(response.status).json(result)
})

Переменные окружения (пример):

MAILOO_API_URL=https://api.mailoo.app
PROJECT_UID=your-project-uid
INTEGRATION_ID=your-form-integration-id
MAILOO_API_KEY=your-api-key
WEBSITE_ORIGIN=https://yourdomain.com

Для Next.js предпочтительнее использовать @mailoo/forms --- см. website-forms-nextjs-example{.interpreted-text role="doc"}.

Форма в браузере (отправка только на ваш сервер)

Минимальные поля HTML: email (обязательно), name (необязательно). JavaScript должен отправлять POST с JSON на ваш маршрут того же происхождения (например, /api/subscribe), а не напрямую в Mailoo с реальным ключом.

Исходящий SMTP и приветственное письмо

Опциональные приветственные или ответные письма используют исходящий SMTP интеграции. Платформенного SMTP по умолчанию нет. Подробнее: outbound-smtp{.interpreted-text role="doc"} и transactional-email{.interpreted-text role="doc"}.

Подписчики и шаблоны (только в панели управления)

Подписчики

: Отображаются в панели управления (e-mail, имя, даты). Для каждой строки: Отписать, Удалить или Восстановить (для отписанных адресов). Внешние сайты не могут читать список подписчиков через API; они только отправляют данные через вебхук формы.

Шаблоны сообщений

: Вкладка интеграции Шаблоны писем (блоки HTML + Liquid). Новые кампании выбирают шаблон; поля формы кампании берутся из слотов campaign. ON_EVENT-кампания используется для welcome и ответа в дашборде. Шаблон не требуется для приёма заявок формой. Рендер --- LiquidJS.

Локализация (как в BLOG)

: Блоки, шаблоны и значения слотов кампании: канонические поля (EN) плюс опциональный JSON locales. Ключи Liquid не локализуются. Передайте locale в form / transactional / lifecycle; при отсутствии или без оверлея --- канонический контент и запись в лог. Массовая рассылка берёт Subscriber.locale. На вкладке шаблонов писем в карточке каждого языка показывается live-превью оверлея (или канонический контент, если поле оверлея пустое).

Отписка

  1. Транзакционная ``{{unsubLink}}`` --- предпочтительный вариант при отправке через transactional-email{.interpreted-text role="doc"}.

  2. Страница подтверждения --- https://mailoo.app/{locale}/unsubscribe/confirm с подписанными параметрами запроса.

  3. API (серверный, с API-ключом):

    POST /api/v1/webhooks/unsubscribe
    Content-Type: application/json
    X-API-Key: your-api-key
    
    {"email": "user@example.com", "integrationId": "your-integration-id"}
    

Кампании (панель управления)

Кампании находятся внутри интеграции формы (вкладка Кампании). Вы можете создавать кампании типа ONE_TIME, ON_EVENT или RECURRING на основе шаблона сообщения, затем открыть Обзор (настройки, живой список активных подписчиков, превью на подписчика, тестовая отправка одним адресом). Обзор не сохраняет аудиторию.

Оболочка шаблона. У шаблона опциональны shellWidthPx (ширина колонки, по умолчанию 600, диапазон 320--800) и shellBackground (фон страницы в hex, по умолчанию #f4f4f5). Блоки --- HTML-фрагменты; Mailoo оборачивает их этой оболочкой при компиляции для отправки и превью в панели.

Приветствие On-Event после новой подписки через форму может отправляться через исходящий SMTP интеграции, когда статус кампании ``SCHEDULED`` (новые кампании создаются как DRAFT). Регистрация и активация идентифицированных пользователей используют события жизненного цикла (user.registered / user.activated) --- см. lifecycle-events{.interpreted-text role="doc"} (то же правило SCHEDULED для USER_REGISTERED / USER_ACTIVATED).

Массовая ONE_TIME. На вкладке Setup задайте скорость рассылки (config.campaignSend.delayBetweenEmailsMs, целое 0...600000; обязательно --- без значения по умолчанию). При необходимости задайте фильтры получателей на кампании (например, зарегистрированы до даты) --- хранятся в recipientFilter и применяются при обзоре аудитории и при копировании подписчиков для отправки. Send Now вызывает POST …/campaigns/{id}/send. Если строк CampaignRecipient ещё нет, API копирует текущих активных подписчиков, подходящих под фильтр кампании (unsubscribedAt null плюс правила recipientFilter), в кампанию и ставит sendRequestedAt. Воркер берёт advisory lock PostgreSQL, ставит SENDING, ждёт короткую паузу после claim и шлёт pending-получателей с заданной паузой. Несколько подов API не могут дважды отправить одну кампанию. При сбое --- FAILED с полным lastError; Retry send (POST …/retry) переводит только failed снова в pending (успешные не пересылаются). PATCH status=SENDING запрещён (400). Тестовая отправка (POST …/test-send) идёт тем же сендером на одного живого подписчика и не ставит кампанию в очередь. RECURRING пока не подключён.

После отправки на вкладке Кампании видны сводные счётчики получателей (в очереди, отправлено, ошибки, доставлено, открыто, клики). Откройте сводку (или Получатели), чтобы увидеть таблицу по каждому адресу со статусом, метками времени и ошибками.

Устранение неполадок

401 --- Invalid API key

: Проверьте ключ, UID проекта и активность ключа. Для ключей RESTRICTED необходима область webhook.form-submission.

403 --- Origin not allowed

: Добавьте источник отправки в Разрешённые источники или очистите список, если проверка Origin не нужна.

429 --- Rate limited

: Уменьшите частоту запросов и повторите; при высоком трафике используйте очередь на своём сервере.

Ошибки валидации

: Обязательным является только email. Необязательные поля: name, subject, content. Не отправляйте поле message, ожидая, что оно станет телом входящего письма --- используйте content.

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

  • Храните API-ключи на сервере; регулярно ротируйте их.
  • Проверяйте e-mail на клиенте и сервере; используйте HTTPS.
  • Обеспечьте понятные пути подписки и отписки.

Следующие шаги

  • website-forms-nextjs-example{.interpreted-text role="doc"} --- BFF @mailoo/forms
  • lifecycle-events{.interpreted-text role="doc"} --- события регистрации / активации в приложении
  • outbound-smtp{.interpreted-text role="doc"} / transactional-email{.interpreted-text role="doc"}
  • contact-feedback-form{.interpreted-text role="doc"} --- CONTACT_FORM для сообщений поддержки
  • OpenAPI: https://api.mailoo.app/docs/v1
📚