Интеграция SendGrid и n8n: dynamic templates, suppressions и event webhook ¶
Обновлено: 2026-05-30
Импортируйте JSON в n8n, замените credentials, домены, sender IDs, лимиты, callback URL и production-политики под вашу инфраструктуру.
Проблема: маркетинговые и сервисные письма часто смешиваются в одном workflow: один retry создаёт дубль, unsubscribe не учитывается, а dynamic_template_data не проходит проверку до отправки.
Решение: интеграция SendGrid и n8n должна разделять transactional и marketing intent, проверять suppressions/consent, валидировать dynamic_template_data и сохранять event webhook в audit-журнале. Такой подход закрывает не демонстрационный happy path, а реальную production-боль: повторы, consent, delivery status, API-ошибки, ограничения провайдера и понятный audit trail.
Проблема: почему простая отправка ломает коммуникации ¶
Коммуникационный workflow нельзя оценивать только по ответу API. Важны consent, формат адреса или телефона, повторная отправка, связь с CRM, callback-статусы и способ отката, если провайдер принял запрос, но сообщение не доставлено.
Для этой страницы основной объект — SendGrid Mail Send request. Входной контракт должен явно фиксировать template_id, to_email, dynamic_template_data, category, asm_group_id, custom_args. Если эти поля приходят нестабильно, автоматизация начинает угадывать и может отправить сообщение не тому получателю, не тем каналом или повторно.
Поэтому workflow строится вокруг детерминированных проверок: сначала validation, consent и idempotency, затем отправка, затем callback/audit и только потом бизнес-действия вроде смены статуса или уведомления менеджера.
Архитектура workflow для n8n ¶
| Блок | Задача | Production-проверка |
|---|---|---|
| App event | получает событие onboarding, invoice или alert | есть customer_id и template_id |
| Consent guard | проверяет transactional/marketing consent | не отправляем marketing без opt-in |
| Template data validator | валидирует dynamic_template_data | нет пустых обязательных ключей |
| Idempotency lookup | отсекает повторную отправку | unique key до Mail Send API |
| SendGrid Mail Send | отправляет письмо через v3 API | template_id, categories, custom_args |
| Event webhook | обновляет delivered/open/bounce/spam report | статус связан с customer_id |
Такой workflow удобно сопровождать: mapping, API-запрос, retry, callback и human-readable audit не смешиваются в одной ноде.
Контракт входных данных ¶
{
"event": "send_onboarding_email",
"to_email": "user@example.com",
"to_name": "Анна",
"template_id": "d-1234567890abcdef1234567890abcdef",
"category": "onboarding",
"customer_id": "cust-1042",
"dynamic_template_data": {
"first_name": "Анна",
"activation_url": "https://example.ru/activate",
"plan": "Pro"
},
"consent": "transactional"
}Payload можно расширять, но нельзя делать обязательные поля “по настроению”. Если источник не передал внешний ID, получателя, шаблон или consent, workflow должен остановиться с понятной ошибкой до отправки.
Code Node: нормализация, mapping и guard-условия ¶
const src = $json.body ?? $json;
const to = String(src.to_email ?? '').trim().toLowerCase();
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(to)) throw new Error(`Invalid to_email: ${to}`);
const templateId = String(src.template_id ?? '').trim();
if (!/^d-[a-f0-9]{32}$/i.test(templateId)) throw new Error('SendGrid dynamic template_id must start with d-');
const consent = String(src.consent ?? '').trim();
if (!['transactional', 'marketing_opt_in'].includes(consent)) {
throw new Error('Invalid email consent type');
}
const data = src.dynamic_template_data ?? {};
for (const key of ['first_name']) {
if (!data[key]) throw new Error(`Missing dynamic_template_data.${key}`);
}
const customerId = String(src.customer_id ?? '').trim();
const idempotencyKey = `sendgrid:${templateId}:${customerId || to}:${src.event ?? 'email'}`;
return [{
json: {
action: 'send_sendgrid_dynamic_template',
idempotency_key: idempotencyKey,
request: {
personalizations: [{
to: [{ email: to, name: src.to_name ?? undefined }],
dynamic_template_data: data,
custom_args: { customer_id: customerId, idempotency_key: idempotencyKey }
}],
from: { email: 'no-reply@example.ru', name: 'Nodbot' },
template_id: templateId,
categories: [String(src.category ?? 'transactional')]
},
consent
}
}];Этот скрипт n8n не заменяет политику провайдера. Его задача — привести данные к стабильному контракту, сформировать idempotency key и не пропустить опасный payload дальше по цепочке.
Готовый workflow JSON: скачать и импортировать ¶
В архиве страницы есть импортируемый workflow JSON и тестовый payload. После импорта замените credentials, домены, sender IDs, callback URL, лимиты и правила доступа. Не запускайте сценарий на production-данных, пока не проверены повторы, пустые значения и ошибки API.
{
"name": "Nodbot - SendGrid dynamic template email with suppression guard",
"nodes": [
{
"name": "App event",
"type": "n8n-node",
"purpose": "получает событие onboarding, invoice или alert"
},
{
"name": "Consent guard",
"type": "n8n-node",
"purpose": "проверяет transactional/marketing consent"
},
{
"name": "Template data validator",
"type": "n8n-node",
"purpose": "валидирует dynamic_template_data"
},
{
"name": "Idempotency lookup",
"type": "n8n-node",
"purpose": "отсекает повторную отправку"
},
{
"name": "SendGrid Mail Send",
"type": "n8n-node",
"purpose": "отправляет письмо через v3 API"
},
{
"name": "Event webhook",
"type": "n8n-node",
"purpose": "обновляет delivered/open/bounce/spam report"
}
],
"connections": "App event → Consent guard → Template data validator → Idempotency lookup → SendGrid Mail Send → Event webhook"
}Пошаговая настройка связки ¶
- Создайте dynamic template в SendGrid и зафиксируйте список обязательных переменных.
- Разделите transactional и marketing workflows, чтобы unsubscribe/consent не ломались бизнес-письмами.
- Сохраните API key в n8n credentials и ограничьте permission только Mail Send/Event Webhook, если это возможно.
- Добавьте durable idempotency storage до SendGrid node или HTTP Request.
- Настройте Event Webhook и записывайте bounce/spam/unsubscribe события обратно в CRM или CDP.
Что проверить после импорта workflow
Откройте каждую ноду, замените credentials и IDs, включите dry-run там, где доступно, затем выполните сценарий на тестовом объекте. Для платных или внешних отправок добавьте approval, rate limit и отдельный тестовый получатель.
Тесты перед production ¶
Минимальный smoke test:
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/sendgrid-dynamic-template-n8n" -H "Content-Type: application/json" --data @integration-sendgrid-n8n-dynamic-template-payload.json- повторный event с тем же customer_id
- template_id без префикса d-
- missing dynamic_template_data
- marketing письмо без opt-in
- bounce event из SendGrid
Отдельно проверьте, что retry n8n не создаёт повторную отправку. Для критичных действий используйте durable storage: Postgres, CRM custom field, audit table или другой слой с уникальным ключом.
Production-риски ¶
- Unsubscribe не учитывается для marketing-писем.
- custom_args не заполняются, и event webhook нельзя связать с клиентом.
- Один workflow шлёт и invoice, и промо-рассылку.
- Dynamic template меняется без regression test.
- Retry после timeout отправляет письмо дважды.
Полезные ссылки и смежные материалы ¶
Внутренняя перелинковка помогает перейти от общего integration-гайда к готовым workflow, а внешние ссылки ведут на официальную документацию API и n8n-нод.
Критерии готовности ¶
- Есть явное разделение transactional и marketing intent.
- template_id и dynamic_template_data проходят validation.
- Повторный event не создаёт вторую отправку.
- Event webhook пишет статусы в audit table.
- Bounce/spam/unsubscribe попадают в alert или suppression policy.