Все статьи
Как тестировать Mailgun webhook на localhost
Mailgunemail webhooksHMAC verificationlocalhost

Как тестировать Mailgun webhook на localhost

Чтобы протестировать Mailgun веб-хуки на localhost, разоблачите своего локального обработчика npx portpreview PORT, настроить конечную точку HTTPS для требуемых типов событий Mailgun и проверить временную метку полезной нагрузки, маркер и HMAC-SHA256 подпись перед принятием события.

Что?Почтовый пистолетОтчет Webhooks

Mailgun отправляет HTTP или HTTPS POST с полезной нагрузкой JSON, когда происходит настроенное событие. Текущие типы событий включают accepted, delivered, temporary_fail, permanent_fail, opened, clickedжалобы на спам и отказ от подписки. Зависимые от отслеживания события появляются только при включенном соответствующем отслеживании.

Тело веб-хука Mailgun Send имеет signature объект рядом event-dataДанные события содержат такие поля, как event, id, timestamp, заголовки сообщений, информация о получателе, теги и детали доставки, в зависимости от типа события. Код против документированных полей и терпимость к отсутствию необязательных свойств. Mailgun Официальный примеры полезной нагрузки Это лучшие приспособления для контрактных испытаний.

Не путайте Mailgun Send webhook с Mailgun. Оповещения. Оповещения используют другой ключ подписи и подписывают весь POST-тело. X-Sign Голова. Это руководство охватывает отправку веб-хуков: поля подписи в полезной нагрузке и учетной записи Webhook Signing Key.

1. Создайте локальную конечную точку Mailgun

В отличие от схем, которые подписывают необработанное тело JSON, документированный расчет Mailgun Send использует временную метку и маркер объекта подписи. Поэтому стандартный анализ JSON является целесообразным. Следующий Express обработчик проверяет HMAC, выполняет проверку возраста повтора и принимает событие.

import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.use(express.json({ limit: '1mb' }));

function verifyMailgunSignature({ timestamp, token, signature }) {
  if (!timestamp || !token || !signature) return false;

  const expected = crypto
    .createHmac('sha256', process.env.MAILGUN_WEBHOOK_SIGNING_KEY)
    .update(String(timestamp) + String(token))
    .digest('hex');

  const expectedBytes = Buffer.from(expected, 'hex');
  const actualBytes = Buffer.from(String(signature), 'hex');
  return expectedBytes.length === actualBytes.length &&
    crypto.timingSafeEqual(expectedBytes, actualBytes);
}

app.post('/webhooks/mailgun', async (req, res) => {
  const signing = req.body?.signature;
  const event = req.body?.['event-data'];

  if (!signing || !event || !verifyMailgunSignature(signing)) {
    return res.status(406).send('invalid webhook');
  }

  const ageSeconds = Math.abs(Date.now() / 1000 - Number(signing.timestamp));
  if (!Number.isFinite(ageSeconds) || ageSeconds > 15 * 60) {
    return res.status(406).send('stale webhook');
  }

  await acceptOnce({
    eventId: event.id,
    replayToken: signing.token,
    payload: event,
  });
  return res.sendStatus(200);
});

app.listen(3000);

15-минутное окно - это политика приложения, а не обязательное значение Mailgun. Mailgun рекомендует проверить, что метка времени не слишком далека от текущего времени, но предупреждает о чрезмерной агрессивности, потому что доставка может быть отложена. Выберите окно, которое соответствует вашим требованиям к очередей и восстановлению инцидентов, отслеживайте законные отказы и намеренно корректируйте его.

ХранитьWebhook подписывает ключв секретном менеджере или переменной среде, никогда не в управлении источником.Почтовый пистолет? Безопасность Webhooks Guide определяет точный расчет: сопоставляет временную метку и маркер без разделителя, вычисляет HMAC-SHA256 с использованием Webhook Signing Key и сравнивает шестидесятичный дайджест с signature.

2 Разоблачение локального хоста по HTTPS

При прослушивании приложения на порту 3000 запустите:

npx portpreview 3000

Добавьте локальный маршрут к общедоступному источнику HTTPS. Например:

https://example.portpreview.dev/webhooks/mailgun

Оставьте приложение и туннель, работающие во время теста. Mailgun нуждается в общедоступном URL-адресе; localhost, частный адрес локальной сети и самоподписанный сертификат разработки не подходят для удаленных пунктов назначения. PortPreview прекращает общедоступный HTTPS и пересылает запрос в ваш локальный порт.

3. Настройка Mailgun URL событий

Mailgun поддерживает конфигурацию webhook на уровне учетной записи и домена. Конечные точки уровня счета могут принимать события через домены и унаследованные субсчета; конечные точки уровня домена применяются только к этому домену. Каждый тип события настроен индивидуально и может иметь до трех URL-адресов. Выберите самую узкую область, которая соответствует вашему приложению.

  1. Откройте область Webhooks для предполагаемой учетной записи или отправки домена.
  2. Выберите тип события, например: delivered или permanent_fail.
  3. Добавьте полную точку HTTPS PortPreview.
  4. Повторите для каждого типа события, который поддерживает ваш обработчик.
  5. Отправьте тест или реальное сообщение и проверьте местные журналы запросов и приложений.

Mailgun дублирует один и тот же URL-адрес для одного и того же события, когда он настроен как на уровне учетной записи, так и на уровне домена, но каждый из разных URL-адресов может получить копию. Наследование родительского счета также может привести к доставке нескольких отдельных конечных точек. Обзор официального Правила конфигурации Перед тем, как отнести каждую дополнительную доставку к повторным запросам.

Как работает проверка подписи Mailgun

The signature Объект содержит:

  • timestampВремя Unix в секундах.
  • token: случайно сгенерированная строка из 50 символов.
  • signature: шестидесятичный дайджест HMAC.
  • parent-signature: необязательно присутствовать для события из субсчета, что позволяет проверить связь с основным счетом, описанную Mailgun.

Для обычной подписи счета вычислите HMAC-SHA256(signingKey, timestamp + token)Нет разделителя, и JSON event-data не является частью этого задокументированного расчета Mailgun Send. Сравните декодированные байты с функцией синхронизации после проверки равной длины. Простая === Сравнение проще, но безопасное по времени сравнение является более безопасным производственным по умолчанию.

Подлинный HMAC доказывает, что сторона, держащая ключ подписи, произвела подпись. Это не доказывает, что эта доставка не была воспроизведена. Mailgun специально рекомендует кэшировать токен и отклонить последующий запрос с тем же токеном. Проверка по временной метке ограничивает, как долго удерживаемый действительный запрос остается полезным. Используйте оба элемента управления: уникальное ограничение для воспроизведения и разумное время для свежести.

Дублировать как поставки, так и эффекты

Сохраняйте два прочных ограничения уникальности: один для токена подписи и один для Mailgun. event-data.idТокен ловит идентичный подписанный повтор доставки. Идентификатор события защищает бизнес-логику, если то же событие отображается в другом действительном контексте доставки. Пространство имен как поставщиком, так и учетной записью или средой.

async function acceptOnce({ eventId, replayToken, payload }) {
  await db.transaction(async (tx) => {
    const tokenWasNew = await tx.webhookTokens.insertIfAbsent({
      provider: 'mailgun',
      token: replayToken,
    });
    if (!tokenWasNew) return;

    const eventWasNew = await tx.webhookEvents.insertIfAbsent({
      provider: 'mailgun',
      eventId,
      receivedAt: new Date(),
    });
    if (!eventWasNew) return;

    await tx.jobs.enqueue({
      type: 'process-mailgun-event',
      payload,
    });
  });
}

Обратно операции вставки-если-отсутствуют с уникальными индексами базы данных; чтение, сопровождаемое вставкой, подвержено гонке при одновременных поставках. Записывайте дедуп-записи и очередей атомарно. Затем быстро распознайте и дайте рабочему обновить состояние сообщения, активировать оповещения или синхронизировать CRM. Видишь? Retry and Idempotency Guide для альтернатив, когда очередь и бизнес-база данных не могут совместно использовать транзакцию.

Mailgun коды ответов и поведение повторных попыток

Почтовый пистолетТекущая документация Send webhook дает три важных результата:

  • 200 Успехов: Mailgun рассматривает webhook POST как успешный и не повторяет его.
  • 406 Неприемлемо: Mailgun относится к ПОСТ как к отвергнутому и не повторяет его.
  • Любой другой код: Для веб-хуков, отличных от уведомлений о доставке, Mailgun повторяется в течение восьми часов через 5 минут, 10 минут, 15 минут, 1 час, 2 часа и 4 часа.

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

Используйте 406 только для запроса, который вы намеренно отклоняете навсегда, например, недействительная подпись или повторение вне политики. Используйте 500 или 503 для переходных сбоев в базе данных и очередей, чтобы подходящие типы веб-хуков могли повторяться. Вернуть 200 только после длительного приема. Возврат 200 при запуске неотслеживаемой фоновой работы может привести к потере события при выходе процесса.

Устранение неполадок Mailgun веб-хук локально

Вычисленные HMAC никогда не совпадают

Подтвердите, что вы используете Webhook подписывает ключ, а не ключ API, пароль SMTP или ключ подписи оповещения. Сопоставьте временную метку и маркер объекта подписи без разграничителя. Изготовить нижний регистр шестнадцатеричного SHA-256 дайджеста. Также убедитесь, что ваш фреймворк не переименовал дефис event-data свойство; запись в скобках позволяет избежать этой ошибки.

Обработчик получает поля форм вместо текущего JSON.

Проверьте, какая функция Mailgun и версия конечной точки генерировали запрос. Не применяйте устаревший учебник полезной нагрузки вслепую к текущему веб-хуку. Тип содержимого журнала, имена полей верхнего уровня и длина тела в разработке без регистрации содержимого сообщения или секретов, а затем реализовать документированный контракт для вашей учетной записи и интеграции.

Mailgun Продолжает повторяться

Проверьте фактический статус, отправленный по проводу. Исключение после фиксации базы данных может превратить ответ в 500, вызвав еще одну попытку. Вот почему вставки идентификатора события и токена должны быть уникальными и долговечными. Если запрос является постоянно недействительным, верните 406; если отказ является временным, исправьте службу и позвольте поведению повторного использования работать.

Ни одно событие не достигает локального хостинга

Подтвердите, что URL-адрес прикреплен к правильной учетной записи или домену и к точному типу события. А. delivered URL не будет получен opened события. Убедитесь, что локальный процесс и туннель все еще активны и что настроенный путь /webhooks/mailgunСледуйте за мной. Руководство по отладке локального webhook отделить конфигурацию провайдера от ошибок маршрутизации и приложений.

Контрольный список безопасности

  • Проверяйте HMAC, прежде чем доверять или регистрировать event-data.
  • Храните ключ подписи в секретном магазине и вращайте его через контролируемое развертывание; никогда не разоблачайте его в коде на стороне клиента.
  • Используйте безопасное по времени сравнение дайджеста, политику метки времени и прочное уникальное ограничение на токен.
  • Проверяйте тип события и требуемые поля до очереди. Относитесь к адресам получателей, субъектам, URL-адресам хранения и пользовательским переменным как к конфиденциальным данным.
  • Принимайте только POST, размер крышки корпуса, используйте HTTPS и сбои с ограничением скорости без блокировки законных запросов Mailgun.
  • Не разоблачайте несвязанные локальные конечные точки администратора или отладки через временное публичное происхождение.
  • Когда тестирование заканчивается, удалите временный URL-адрес и настройте стабильную конечную точку производства.

Mailgun также документирует дополнительный сертификат клиента TLS по запросам веб-хука, когда ваш принимающий сервер имеет действительный TLS. Это может обеспечить проверку на транспортном уровне, но не заменяет проверку полезной нагрузки HMAC, контроль повтора и авторизацию приложений. Контроль уровня в соответствии с вашей моделью угрозы.

Испытания на приемку продукции

  1. Доставьте действительное подписанное устройство и подтвердите одно длительное событие плюс ответ 200.
  2. Измените токен без изменения подписи и подтвердите 406 без записи события.
  3. Повторите правильное тело и не подтвердите вторую работу или побочный эффект.
  4. Отправьте действительную подпись с меткой времени за пределы настроенного окна и проверьте предполагаемый отказ.
  5. Вызовите временную ошибку базы данных, подтвердите ответ не 200/не 406, затем восстановите базу данных и проверьте одно успешное принятие.
  6. Упражняйтесь каждый сконфигурированный Mailgun тип события, потому что поля полезной нагрузки и ожидания повторного использования различаются.

Как только эти тесты пройдут, используйте тот же путь проверки и дедупликации в производстве. Чтобы получить независимое от поставщика объяснение сравнения HMAC и секретной обработки, прочитайте Руководство по проверке подписи web-cook.

Часто задаваемые вопросы

Может ли Mailgun отправлять веб-хуки в Localhost?
Mailgun не может достичь локального хоста напрямую. Запустите `npx portpreview PORT`, добавьте свой маршрут веб-хука к генерируемому источнику HTTPS и настройте этот общедоступный URL для каждого требуемого типа события Mailgun.
Как проверить подпись Mailgun Send?
Сопоставьте временную метку и маркер объекта полезной нагрузки без разделителя, вычислите HMAC-SHA256 шестнадцатеричный дайджест с использованием Webhook Signing Key и сравните его с поставляемой подписью с использованием безопасного по времени сравнения.
Как предотвратить повторные атаки Mailgun?
Храните каждый токен подписи под прочным уникальным ограничением и отклоните уже увиденный токен. Также соблюдайте разумную политику временных меток, предоставляя достаточно времени для законных задержек доставки и ваших эксплуатационных требований.
Когда Mailgun повторит неудачный веб-хук?
Mailgun рассматривает 200 как успех, а 406 как постоянный отказ. Для других ответов веб-хуки, кроме уведомлений о доставке, используют документированные интервалы повторного использования в течение примерно восьми часов, поэтому обработчики должны быть идемпотентными.