Unify SMTP2GO email and SMS into one webhook URL.
Deploy Beta / unit-tests (push) Successful in 13s
Deploy Beta / docker (push) Successful in 18s
Deploy Beta / deploy-beta (push) Successful in 1m38s

Classify payloads on /webhooks/smtp2go/ so one SMTP2GO webhook covers both channels under the 10-webhook limit; keep /email/ and /sms/ as aliases and harden SMS event matching.
This commit is contained in:
2026-08-10 11:06:37 -05:00
parent f7f3174e1c
commit ee28dcabab
7 changed files with 472 additions and 115 deletions
+27 -22
View File
@@ -4,8 +4,8 @@ Campaign compose/send, SMTP2GO email + SMS, PCM Integrations postcards, and deli
## SMTP2GO webhook setup
Campaign report page polls provider events every 10s. Create **two** webhooks in
SMTP2GO → **Settings → Webhooks** (email and SMS stay separate).
Campaign report page polls provider events every 10s. Create **one** SMTP2GO
webhook (email + SMS share a URL — paid plans cap at 10 webhooks).
### Auth (`SMTP2GO_WEBHOOK_SECRET`)
@@ -14,35 +14,39 @@ SMTP2GO → **Settings → Webhooks** (email and SMS stay separate).
(do not leave it as “None”).
3. Fallback: `?token=<SMTP2GO_WEBHOOK_SECRET>` on the webhook URL also works.
### Email webhook
### Unified email + SMS webhook
| Field | Value |
|-------|--------|
| URL | `https://mkdrealtor.com/portal/messaging/webhooks/email/` |
| URL | `https://mkdrealtor.com/portal/messaging/webhooks/smtp2go/` |
| Authorization header | **Bearer** + `SMTP2GO_WEBHOOK_SECRET` |
| Output type | JSON |
| Users | email SMTP user(s) **and** the SMS API key (`SMTP2GO_SMS_API_KEY`) |
| Email events | processed, bounced, rejected, spam, delivered, unsub/resub, opened, clicked |
| Email headers | `X-Monica-Message-Id` |
| SMS events | leave unchecked |
| SMS events | Submitted, Sending, Delivered, Failed, Rejected (and Opt-out if shown) |
`X-Monica-Message-Id` is set on every campaign email send and is required so webhook
events match the correct recipient row. Invalid / missing header values no longer
500 the endpoint (SMTP2GO “Test this webhook” often sends a sample non-UUID).
The handler classifies each POST from the payload (`sms_*` / `destination_number`
→ SMS; `rcpt` / `email_id` / `X-Monica-Message-Id` → email; inbound `text=STOP`
without `event` → SMS opt-out).
`X-Monica-Message-Id` is set on every campaign email send and is required so email
webhook events match the correct recipient row. Invalid / missing header values
no longer 500 the endpoint (SMTP2GO “Test this webhook” often sends a sample
non-UUID).
SMS correlation uses `message_id` (SMS id), then `destination_number` phone
fallback. Do **not** treat webhook `id` as the SMS id.
**Opt-out:** SMTP2GO auto-handles replies `STOP` / `UNSUB` / `UNSUBSCRIBE`.
This endpoint also accepts inbound POSTs without an `event` field
(`text=STOP`, `from=…`) and opts the contact out of SMS. Later sends to
opted-out numbers are typically `sms_rejected`.
Beta / other hosts: swap the hostname, keep the path.
### SMS webhook (separate)
| Field | Value |
|-------|--------|
| URL | `https://mkdrealtor.com/portal/messaging/webhooks/sms/` |
| Authorization header | **Bearer** + same `SMTP2GO_WEBHOOK_SECRET` |
| Output type | JSON |
| Email events | leave unchecked |
| SMS events | Submitted, Sending, Delivered, Failed, Rejected, Opt-out |
This endpoint also accepts inbound reply POSTs (`text=STOP`, `from=…`) and opts the
contact out of SMS.
Legacy aliases (same handler): `/portal/messaging/webhooks/email/` and
`/portal/messaging/webhooks/sms/` — prefer `/smtp2go/` for new configs.
## PCM Integrations (postcards)
@@ -119,8 +123,9 @@ PCM_RETURN_ADDRESS={…}
| Path | Purpose |
|------|---------|
| `POST /portal/messaging/webhooks/email/` | Email delivery / open / click / bounce / … |
| `POST /portal/messaging/webhooks/sms/` | SMS delivery events + inbound STOP |
| `POST /portal/messaging/webhooks/smtp2go/` | Unified SMTP2GO email + SMS (+ inbound STOP) |
| `POST /portal/messaging/webhooks/email/` | Legacy alias → same as `/smtp2go/` |
| `POST /portal/messaging/webhooks/sms/` | Legacy alias → same as `/smtp2go/` |
| `POST /portal/messaging/webhooks/postcard/` | PCM order / mail tracking events |
| `GET /portal/messaging/campaigns/<id>/status.json` | Live stats for the campaign report UI |
| `GET /portal/messaging/postcard/` | PCM designer iframe |