Kommo + SendGrid: транзакционные email из воронки продаж

Kommo + SendGrid: транзакционные email из воронки продаж

Twilio SendGrid - стандарт для транзакционных email в B2B SaaS: Dynamic Templates с Handlebars, Event Webhook для отслеживания, delivery rate SLA 99.9%. Нативной интеграции с Kommo нет. Строим через SendGrid Mail Send API v3.

Что строим

  1. Won deal -> отправить onboarding email через SendGrid Dynamic Template
  2. SendGrid Event Webhook -> открытие/клик/bounce -> Note в Kommo
  3. Комплексный сценарий: серия email по этапам воронки без внешнего ESP-автоматизатора

Аутентификация

SendGrid использует Bearer token (API Key):

import requests

SENDGRID_API_KEY = "SG.your_api_key"

sg_session = requests.Session()
sg_session.headers.update({
    "Authorization": f"Bearer {SENDGRID_API_KEY}",
    "Content-Type": "application/json",
})

SEND_URL = "https://api.sendgrid.com/v3/mail/send"

API Key создаётся в SendGrid Dashboard -> Settings -> API Keys. Минимальные права для отправки: Mail Send (Full Access).

Отправка через Dynamic Template

def send_onboarding_email(to_email: str, to_name: str, template_data: dict, deal_id: int) -> str:
    """Send email via SendGrid Dynamic Template. Returns message ID."""
    payload = {
        "from": {
            "email": "hello@exceltic.dev",
            "name":  "Exceltic",
        },
        "personalizations": [
            {
                "to": [{"email": to_email, "name": to_name}],
                "dynamic_template_data": {
                    **template_data,
                    "kommo_deal_id": str(deal_id),  # для трекинга в webhook
                },
                "custom_args": {
                    "kommo_deal_id": str(deal_id),  # передаётся в каждом Event
                },
            }
        ],
        "template_id": "d-your_template_id",  # Template ID из SendGrid
        "tracking_settings": {
            "click_tracking": {"enable": True},
            "open_tracking":  {"enable": True},
        },
        "mail_settings": {
            "bypass_list_management": {"enable": False},
        },
    }
    r = sg_session.post(SEND_URL, json=payload)
    r.raise_for_status()
    # SendGrid возвращает 202 без тела. Message ID в заголовке X-Message-Id
    return r.headers.get("X-Message-Id", "")

custom_args - ключевой инструмент: эти поля возвращаются в каждом Event от Event Webhook. Так вы знаете, к какой сделке Kommo относится событие без внешней БД.

Event Webhook: отслеживание открытий

SendGrid отправляет массив событий на ваш URL при каждом delivered, opened, clicked, bounced, unsubscribed.

Верификация подписи ECDSA:

SendGrid подписывает webhook через ECDSA (не HMAC). Это нестандартно - большинство webhook используют HMAC-SHA256.

from ecdsa import VerifyingKey, NIST256p
from ecdsa.util import sigdecode_der
import base64, hashlib
from flask import Flask, request, abort

app = Flask(__name__)

# Публичный ключ из SendGrid Dashboard -> Settings -> Mail Settings -> Event Webhook
SG_VERIFICATION_KEY = "MFkwEwYHKoZIzj0CAQY..."  # base64 DER-encoded public key

def verify_sendgrid_signature(payload: bytes, timestamp: str, signature: str) -> bool:
    """Verify SendGrid Event Webhook ECDSA signature."""
    vk = VerifyingKey.from_der(base64.b64decode(SG_VERIFICATION_KEY))
    signed_payload = timestamp.encode() + payload
    digest = hashlib.sha256(signed_payload).digest()
    try:
        return vk.verify_digest(
            base64.b64decode(signature),
            digest,
            sigdecode=sigdecode_der,
        )
    except Exception:
        return False

@app.route("/sendgrid/events", methods=["POST"])
def sendgrid_events():
    timestamp = request.headers.get("X-Twilio-Email-Event-Webhook-Timestamp", "")
    signature = request.headers.get("X-Twilio-Email-Event-Webhook-Signature", "")

    if not verify_sendgrid_signature(request.get_data(), timestamp, signature):
        abort(401)

    events = request.json  # массив событий
    for event in events:
        process_event(event)

    return "ok", 200

def process_event(event: dict):
    event_type  = event.get("event", "")        # "delivered", "open", "click", "bounce"
    deal_id_str = event.get("kommo_deal_id", "")  # из custom_args
    email       = event.get("email", "")
    url         = event.get("url", "")           # только для "click"
    reason      = event.get("reason", "")        # только для "bounce"

    if not deal_id_str:
        return

    deal_id = int(deal_id_str)

    if event_type == "open":
        add_kommo_note(deal_id, f"Email открыт: {email}")
    elif event_type == "click":
        add_kommo_note(deal_id, f"Клик по ссылке: {url}")
    elif event_type in ("bounce", "dropped", "blocked"):
        add_kommo_note(deal_id, f"Email не доставлен ({event_type}): {reason}")
        create_kommo_task(deal_id, f"Проверить email клиента: {email}")

ecdsa библиотека: pip install ecdsa. Без верификации - webhook доступен любому, кто знает URL.

Серия email по этапам воронки

Вместо внешнего ESP-автоматизатора (дополнительные затраты) - логика на стороне вашего сервиса:

STAGE_TEMPLATES = {
    PROPOSAL_STAGE_ID:   "d-template_proposal",
    NEGOTIATION_STAGE_ID:"d-template_followup",
    WON_STAGE_ID:        "d-template_onboarding",
}

@app.route("/kommo/stage-webhook", methods=["POST"])
def kommo_stage_webhook():
    data = request.json
    for lead in data.get("leads", {}).get("update", []):
        new_status = lead.get("status_id")
        deal_id    = lead["id"]

        if new_status in STAGE_TEMPLATES:
            contact = get_kommo_deal_contact(deal_id)
            send_onboarding_email(
                to_email=contact["email"],
                to_name=contact["name"],
                template_data={"deal_name": lead.get("name", "")},
                deal_id=deal_id,
            )
    return "ok", 200

Одна точка интеграции - все email-триггеры управляются через конфиг STAGE_TEMPLATES.

Реальный кейс

EU SaaS-компания с 60-70 сделок в месяц отправляла onboarding email вручную через SendGrid UI. 12-15% сделок теряли email из-за человеческой ошибки (забыли отправить, неверный шаблон).

После интеграции:

  • Onboarding email отправляется автоматически при переходе в Won (задержка < 5 секунд)
  • Bounce-события создают задачи менеджеру немедленно
  • Open tracking обновляет поле в Kommo - менеджер видит, читал ли клиент письмо

За первые 3 месяца: 0 пропущенных onboarding email, 23% рост response rate.

Для кого подходит

SaaS и B2B-команды, которые уже используют SendGrid для транзакционных email и хотят замкнуть петлю обратной связи в CRM. Особенно актуально когда нужен event-tracking (открытия, клики) в контексте конкретной сделки.

Для полноценной email-автоматизации с визуальным редактором - см. Kommo + Customer.io или Kommo + Loops.

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

Чем Dynamic Templates отличаются от Legacy Templates?

Dynamic Templates используют Handlebars {{variable}} синтаксис и управляются через Design Editor в SendGrid. Legacy Templates устарели и используют {{%variable%}}. Для всех новых интеграций - только Dynamic Templates. Template ID начинается с d-.

Как настроить отдельный webhook для tracking vs transactional events?

SendGrid позволяет один Event Webhook URL на аккаунт. Разделение через custom_args: добавьте "event_category": "tracking" или "transactional" и фильтруйте в обработчике. Или используйте subusers - у каждого свой Event Webhook.

Нужна ли IP Warmup для отправки?

Если отправляете с выделенного IP - да, нужна warmup. Если через shared IP pool (по умолчанию) - нет. Для объёмов до 100K писем в месяц shared IP достаточно. Выделенный IP рекомендуется от 200K+ или если нужна полная изоляция репутации.

Как обработать unsubscribe в Kommo?

Event unsubscribe от SendGrid содержит email. Обработчик находит контакт в Kommo по email и ставит тег email_unsubscribed или обновляет кастомное поле. При следующей отправке сервис проверяет этот тег и пропускает контакт.

Итог

Интеграция Kommo + SendGrid даёт замкнутый цикл email-коммуникации в CRM:

  • Bearer token для отправки, custom_args для передачи deal_id в события
  • Event Webhook: ECDSA-верификация через X-Twilio-Email-Event-Webhook-Signature
  • Open/click/bounce -> Note в Kommo без ручной работы
  • Серия email по этапам воронки без внешнего автоматизатора

Если SendGrid уже в вашем стеке и нужно замкнуть события на Kommo - опишите задачу команде Exceltic.dev.

Ещё статьи

Все →