Unignore site/ (was blocked by mkdocs /site rule), add compose/Docker/uv tooling, and split deploys so push to main goes to beta while prod stays manual.
4.0 KiB
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 two webhooks in SMTP2GO → Settings → Webhooks (email and SMS stay separate).
Auth (SMTP2GO_WEBHOOK_SECRET)
- Set
SMTP2GO_WEBHOOK_SECRETin.env/ prod env (long random string). - In SMTP2GO, set Authorization header to Bearer and paste that same secret (do not leave it as “None”).
- Fallback:
?token=<SMTP2GO_WEBHOOK_SECRET>on the webhook URL also works.
Email webhook
| Field | Value |
|---|---|
| URL | https://mkdrealtor.com/portal/messaging/webhooks/email/ |
| Authorization header | Bearer + SMTP2GO_WEBHOOK_SECRET |
| Output type | JSON |
| Email events | processed, bounced, rejected, spam, delivered, unsub/resub, opened, clicked |
| Email headers | X-Monica-Message-Id |
| SMS events | leave unchecked |
X-Monica-Message-Id is set on every campaign email send and is required so webhook
events match the correct recipient row.
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.
PCM Integrations (postcards)
Default postcard provider. Designer embeds PCM’s editor; orders use DirectMail API v3.
Env
| Var | Purpose |
|---|---|
PCM_API_KEY |
Bearer token for https://v3.pcmintegrations.com |
PCM_WEBHOOK_SECRET |
Auth for inbound status webhooks |
PCM_RETURN_ADDRESS |
JSON return address on orders |
POSTCARD_PROVIDER |
pcm (default) |
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
Create a webhook subscription in the PCM dashboard (Working with Webhooks):
| Field | Value |
|---|---|
| URL | https://mkdrealtor.com/portal/messaging/webhooks/postcard/ |
| Authorization | Bearer + PCM_WEBHOOK_SECRET |
| Events | Order / recipient status (Pending, Processing, Processed, Delivered, Undeliverable, Canceled) |
| Environments | Sandbox and/or Production as needed |
Fallback: ?token=<PCM_WEBHOOK_SECRET> on the URL.
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):
# 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_WEBHOOK_SECRET=…
PCM_RETURN_ADDRESS={…}
Endpoints (app)
| 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/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.