Files
print_forge/site/directmail
westfarn c9b81ceed7
CI / test (pull_request) Successful in 35s
Add customer accounts, shipment tracking, and purchase reviews.
Shoppers can register, save shipping details, and view order history while cards stay on Stripe. EasyPost tracker updates (including numbers from Pirate Ship) and 1–5 star reviews are limited to buyers. The contact form now only asks for email and a message.
2026-09-07 06:37:52 -05:00
..
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00
2026-09-06 04:27:41 -07:00

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).

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).

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):

# 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.