Files
monica_site/site/messaging/README.md
T
2026-08-30 19:25:03 -05:00

151 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Messaging
Campaign compose/send, SMTP2GO email + SMS, PCM Integrations postcards, and delivery webhooks.
## SMTP2GO webhook setup
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`)
1. Set `SMTP2GO_WEBHOOK_SECRET` in `.env` / prod env (long random string).
2. In SMTP2GO, set **Authorization header** to **Bearer** and paste that same secret
(do not leave it as “None”).
3. Fallback: `?token=<SMTP2GO_WEBHOOK_SECRET>` on the webhook URL also works.
### Unified email + SMS webhook
| Field | Value |
|-------|--------|
| 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 | Submitted, Sending, Delivered, Failed, Rejected (and Opt-out if shown) |
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).
## Campaign tracked links (UTM + piha.li)
Composer auto-inserts a homepage link:
| Param | Value |
|-------|--------|
| `utm_source` | `monica` |
| `utm_medium` | `email` / `sms` / `postcard` |
| `utm_campaign` | hyphenated campaign name |
When `SHORTENER_BASE_URL` + `SHORTENER_API_TOKEN` are set, the app POSTs that
long HTTPS URL to `url_shortening_service` (`POST /api/links/`, Bearer
`monica:<secret>`) and puts `short_url` (`https://piha.li/<code>`) in SMS,
email hrefs, and postcard QR codes. Empty env → long UTM URL (local default).
Mint against the short host (`https://piha.lc` / `https://beta.piha.li`). See `.env.example` / `.env.prod.example`.
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.
Legacy aliases (same handler): `/portal/messaging/webhooks/email/` and
`/portal/messaging/webhooks/sms/` — prefer `/smtp2go/` for new configs.
## PCM Integrations (postcards)
Default postcard provider. Designer embeds PCMs editor; orders use DirectMail API v3.
### Env
| Var | Purpose |
|-----|---------|
| `PCM_API_KEY` | API key from PCM portal (My Account → API Keys) |
| `PCM_API_SECRET` | Matching API secret; used with key on `POST /auth/login` |
| `PCM_CHILD_REF_NBR` | Optional child-app ref for multi-account |
| `PCM_WEBHOOK_SECRETS` | Comma-separated signature secrets (one per PCM subscription) |
| `PCM_WEBHOOK_SECRET` | Optional single-secret alias (merged into the list above) |
| `PCM_RETURN_ADDRESS` | JSON return address on orders |
| `POSTCARD_PROVIDER` | `pcm` (default) |
Auth flow: `POST /auth/login` with `{apiKey, apiSecret}` → short-lived
`token` used as `Authorization: Bearer …` on design/order calls
([PCM Logging In](https://docs.pcmintegrations.com/docs/directmail-api/ffef03a112bb0-logging-in)).
### Designer
Portal → **Postcard design**: create/list designs via API, edit in iframe
(`POST /design/custom`, `GET /design/{id}/edit?mode=embed`). Save as a
`MessageTemplate` (stores `design_id`) then pick it when composing a postcard campaign.
### Postcard webhook
PCM allows **one event per subscription**, and each subscription gets its own
**signature secret** (copy-only in the UI). Create one subscription per status
you care about; point them all at the same URL and paste every secret into env.
| Field | Value |
|-------|--------|
| URL | `https://mkdrealtor.com/portal/messaging/webhooks/postcard/` |
| Events | One subscription each: Pending, Processing, Processed, Delivered, Undeliverable, Canceled (skip QrCodeScan unless needed) |
| Environments | Sandbox and/or Production as needed |
| Secrets | Copy each subscription signature → `PCM_WEBHOOK_SECRETS=sec1,sec2,…` |
We accept Bearer, `?token=`, or common signature headers (raw secret or
HMAC-SHA256 of body) matching **any** listed secret.
Correlation: we send `extRefNbr=<Message.uuid>` on each recipient; webhooks should
echo that (or `orderID`, matched to `Message.provider_message_id`).
### Campaign completion email
When a campaign reaches **completed** (email, SMS, or postcard), one summary email
goes to `campaign.created_by.email`, else `CONTACT_EMAIL`. Guarded by
`Campaign.notify_sent_at` so it only sends once.
### Local development
SMTP2GO / PCM cannot reach `localhost`. Use a tunnel (Cloudflare Tunnel / ngrok) to `:8000`,
or test webhooks against beta/prod.
For real SMTP delivery locally (not console logs):
```bash
# in .env
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
SMTP2GO_WEBHOOK_SECRET=
SMTP2GO_SMS_API_KEY=# SMS sends only
PCM_API_KEY=
PCM_API_SECRET=
PCM_WEBHOOK_SECRETS=sec1,sec2,…
PCM_RETURN_ADDRESS={}
```
### Endpoints (app)
| Path | Purpose |
|------|---------|
| `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 |
Code: `webhooks.py`, `providers/postcard/pcm.py`, `views.py`.