Як надійно отримувати Event Webhook від SendGrid
Event Webhook від SendGrid надсилає на джерело Railhook пакети подій доставки (delivered, bounce, open, click). Джерело перевіряє підпис, зберігає кожен пакет таким, яким той надійшов, і пересилає його у ваш сервіс із повторними спробами.
Чому вебхукам SendGrid потрібен буфер
Section titled “Чому вебхукам SendGrid потрібен буфер”SendGrid чекає на 2xx. Якщо не дочекався, повторює з дедалі більшими інтервалами протягом доби від моменту події, а потім припиняє. (SendGrid: Getting started with the Event Webhook)
На цих подіях тримаються обробка повернень і скарг на спам та списки відмов. Подія, викинута через добу, означає відмову, яку ви так і не застосували. Коли попереду стоїть Railhook:
- Railhook відповідає SendGrid, щойно збереже пакет, тож через ваш застосунок жодна подія у вікно повторів SendGrid не потрапляє.
- Ваш сервіс отримує до 5 спроб на кожне пересилання з інтервалами від 1 хвилини до 1 години, а те, що так і не вдалося доставити, потрапляє в «Недоставлені пересилання».
- Будь-що збережене можна відтворити ще за кілька днів після того, як SendGrid уже здався б.
Підключення SendGrid
Section titled “Підключення SendGrid”Знадобляться проєкт Railhook і API-ключ. Ті самі кроки є в панелі керування, у розділі «Вхідні».
export RAILHOOK_URL=https://railhook.io # or your own instanceexport RAILHOOK_API_KEY=...export PROJECT_ID=...-
Створіть джерело Railhook, щоб отримати адресу, на яку SendGrid має надсилати запити:
Terminal window curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources" \-H "X-API-Key: $RAILHOOK_API_KEY" \-H "Content-Type: application/json" \-d '{"name":"SendGrid","providerType":"SENDGRID","verificationMode":"NONE"}'Збережіть
idтаingressUrlз відповіді. -
Створіть вебхук у SendGrid. Відкрийте Settings → Mail Settings → Event Webhooks і створіть новий вебхук. Вкажіть
ingressUrlу полі Post URL, а в Actions to be posted виберіть потрібні типи подій. (SendGrid: Event Webhook security features) -
Увімкніть підпис і збережіть. У секції Security features увімкніть Enable Signed Event Webhook і натисніть Save. Пара ключів створюється саме під час збереження, тож перевірка до збереження перевіряє непідписаний вебхук. Відкрийте вебхук ще раз і скопіюйте verification key, який там з’явиться.
-
Передайте ключ Railhook і ввімкніть перевірку:
Terminal window curl -X PUT "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources/$SOURCE_ID" \-H "X-API-Key: $RAILHOOK_API_KEY" \-H "Content-Type: application/json" \-d '{"name":"SendGrid","verificationMode":"PROVIDER","hmacSecret":"'"$SENDGRID_VERIFICATION_KEY"'"}'Вставляйте його в тому вигляді, як показує SendGrid, або обгорнутим у
-----BEGIN PUBLIC KEY-----; Railhook прочитає обидва варіанти. -
Додайте призначення, адресу вашого сервісу:
Terminal window curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources/$SOURCE_ID/destinations" \-H "X-API-Key: $RAILHOOK_API_KEY" \-H "Content-Type: application/json" \-d '{"url":"https://api.example.com/webhooks/sendgrid","authType":"BEARER","authConfig":"{\"token\":\"...\"}","enabled":true}' -
Перевірте інтеграцію кнопкою Test Your Integration, уже після збереження. Зразковий пакет з’явиться в розділі «Вхідні → Отримані», з одним пересиланням на кожне призначення.
Як перевіряється підпис
Section titled “Як перевіряється підпис”SendGrid підписує байти мітки часу, за якими одразу йде необроблене тіло, алгоритмом ECDSA над SHA-256 і надсилає:
X-Twilio-Email-Event-Webhook-Signature: підпис у форматі DER, закодований у Base64;X-Twilio-Email-Event-Webhook-Timestamp: секунди від початку епохи.
Railhook перевіряє це відкритим ключем. Пакет, який не пройшов перевірку, отримує 401 і не зберігається.
Дедуплікуйте за подією, а не за запитом
Section titled “Дедуплікуйте за подією, а не за запитом”Запит SendGrid є JSON-масивом подій, і кожна має власний sg_event_id. Ідентифікатора самого пакета немає, тож для джерела SendGrid Railhook не записує providerEventId і запити не дедуплікує: ключ за першою подією пакета втратив би решту, якби SendGrid під час повторної спроби перезібрав пакет інакше.
Дедуплікуйте у власному обробнику за sg_event_id кожної окремої події, як радить SendGrid.
Що отримує ваш сервіс
Section titled “Що отримує ваш сервіс”Тіло точно таким, яким його надіслав SendGrid, байт у байт: масив, а не одна подія на запит. Ваш обробник проходить його циклом. Заголовки з підписом не пересилаються; ваш сервіс автентифікує Railhook обліковими даними призначення. Див. Призначення.
Локальна розробка з CLI
Section titled “Локальна розробка з CLI”-
Встановіть CLI й увійдіть, як описано в розділі CLI, а потім відкрийте тунель до порту застосунку:
Terminal window railhook listen 3000 -
Додайте джерелу друге призначення з надрукованою публічною адресою й вашим маршрутом у кінці, наприклад
https://<host>/tunnel/<slug>/webhooks/sendgrid. Вона веде наhttp://localhost:3000/webhooks/sendgrid. -
Натисніть Test Your Integration у SendGrid або надішліть собі справжнього листа, і пакет прийде у ваш локальний застосунок. Вимкніть це призначення, коли закриєте тунель.
Відтворення після збою
Section titled “Відтворення після збою”Кожен відтворений пакет іде на всі призначення джерела як нове пересилання:
curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-events/bulk-replay" \ -H "X-API-Key: $RAILHOOK_API_KEY" \ -H "Content-Type: application/json" \ -d '{"sourceId":"'"$SOURCE_ID"'","from":"2026-09-18T10:00:00Z","to":"2026-09-18T14:00:00Z","verified":true}'Відтворити можна все, що ще зберігається: 7 днів у Railhook Cloud і скільки налаштуєте на власному сервері. Оскільки запити SendGrid не дедуплікуються, відтворення надішле події, які ваш обробник уже бачив: ще одна причина ключувати його за sg_event_id. Див. Відтворення.