docs: add MPS-23 ticket — consolidated transactional sender identity
This commit is contained in:
parent
f4be4f4612
commit
0f19da5ba8
2 changed files with 82 additions and 0 deletions
|
|
@ -235,6 +235,7 @@ mps_page_session (raw rows)
|
|||
| [MPS-20](tickets/mps-20.md) | Auction House Mode (eBay-style Bidding) | Complete |
|
||||
| [MPS-21](tickets/mps-21.md) | Make-an-Offer Mode | Complete |
|
||||
| [MPS-22](tickets/mps-22.md) | Kill-Switch Feature Flags — Karaoke + Torrent Off by Default | Complete |
|
||||
| [MPS-23](tickets/mps-23.md) | Consolidated Transactional Sender Identity + Shop Contact Email | Open |
|
||||
|
||||
## Related Docs
|
||||
|
||||
|
|
|
|||
81
docs/tickets/mps-23.md
Normal file
81
docs/tickets/mps-23.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# MPS-23 — Consolidated transactional sender identity + shop contact email
|
||||
|
||||
**Status:** Open (DNS prep done; needs a decision on the Reply-To / shop-contact-email approach before code lands)
|
||||
|
||||
## Problem
|
||||
|
||||
MPS sends each shop's transactional mail (OTP login codes, purchase receipts,
|
||||
sale notifications, gift cards, offers, invites) `From: no-reply@<request.domain>`
|
||||
— i.e. from the shop's *own* hostname:
|
||||
|
||||
- `my.makepostsell.com` → `no-reply@my.makepostsell.com`
|
||||
- `<shop>.makepostsell.com` → `no-reply@<shop>.makepostsell.com`
|
||||
- operator custom domain `shop.unturf.com` → `no-reply@shop.unturf.com`
|
||||
|
||||
For operator custom domains, MPS controls no DKIM key for that domain and the
|
||||
domain's SPF doesn't authorize MPS's sending infrastructure, so the mail is
|
||||
**unauthenticated** (no DKIM, no SPF pass) → Gmail spam-folders it. Even
|
||||
`no-reply@my.makepostsell.com` lands in spam on first contact because
|
||||
`makepostsell.com` is a cold direct-signing identity (its mail historically
|
||||
went through Mailgun's `mg.makepostsell.com`, never `makepostsell.com` itself).
|
||||
|
||||
Background: 2026-05-12 mail-infra work moved both origin boxes
|
||||
(`origin.makepostsell.com`, `origin.remarkbox.com`) to DKIM-sign at origin and
|
||||
relay through `mx1.foxhop.net` (warm IP). `my.makepostsell.com` / `*.makepostsell.com`
|
||||
/ `remarkbox.com` mail now passes SPF+DKIM+DMARC. Operator-custom-domain shops
|
||||
are the remaining gap, and even the makepostsell ones benefit from one
|
||||
consistent warmed identity.
|
||||
|
||||
## Fix
|
||||
|
||||
Send **all** MPS transactional mail from one warm, authenticated identity:
|
||||
`no-reply@origin.makepostsell.com`.
|
||||
|
||||
- opendkim on `origin.makepostsell.com` already signs `*@*.makepostsell.com`
|
||||
with `d=makepostsell.com` → `no-reply@origin.makepostsell.com` is signed
|
||||
(DMARC-aligned at the `makepostsell.com` org-domain level under relaxed mode).
|
||||
- `origin.makepostsell.com` SPF record (added in `proxy.unturf.com/ingress/pdns-init.sh`):
|
||||
`v=spf1 a a:mx1.foxhop.net -all` → authorizes the origin box + the mx1 relay.
|
||||
- Result: every shop's mail → DKIM-signed, SPF-pass, DMARC-pass, delivered
|
||||
from mx1's warm IP — independent of which shop/domain it's for.
|
||||
|
||||
Recipient clarity: put the shop name in the display name —
|
||||
`From: "Acme Shop" <no-reply@origin.makepostsell.com>`.
|
||||
|
||||
## Open question — Reply-To / customer support
|
||||
|
||||
Shops have no contact email today (`Shop` model has no email/contact column).
|
||||
If a customer replies to an OTP/receipt it hits `no-reply@…` and vanishes.
|
||||
Options:
|
||||
|
||||
1. **Add `Shop.support_email`** (nullable) + a field in `shop-settings`; set
|
||||
`Reply-To: <support_email>` when the operator has filled it in. Opt-in,
|
||||
privacy-safe. *(recommended)*
|
||||
2. Catch-all `reply@origin.makepostsell.com` → forward to the shop owner's
|
||||
account email. Requires inbound mail handling + a mapping table.
|
||||
3. Default `Reply-To` to the shop owner's user email. Simple, but leaks the
|
||||
owner's personal address.
|
||||
|
||||
Until decided: ship without `Reply-To` (honest — it's `no-reply@`).
|
||||
|
||||
## Implementation
|
||||
|
||||
- **Config:** `app.email.sender = no-reply@origin.makepostsell.com` in
|
||||
`data/development.ini` + the prod pillar (`foxhop-pillar/uwsgi/makepostsell/init.sls`).
|
||||
`lib/mail.py:send_pyramid_email` already reads `request.app.get("email.sender", …)`.
|
||||
- **`lib/mail.py`:** extract `_build_from_header(request, sender_email)` →
|
||||
`email.utils.formataddr((display_name, sender_email))`, `display_name` =
|
||||
`request.shop.name` when a shop is in context, else the site name. Add
|
||||
`Reply-To` per the chosen option. Use the helper in `send_email`/`send_pyramid_email`.
|
||||
- **DNS (done):** `origin.makepostsell.com|TXT|v=spf1 a a:mx1.foxhop.net -all`.
|
||||
- **Optional hardening:** dedicated DKIM key for `origin.makepostsell.com`
|
||||
(publish `<sel>._domainkey.origin.makepostsell.com`, add to opendkim) so the
|
||||
signature is `d=origin.makepostsell.com` — author-domain-exact rather than
|
||||
org-aligned. Marginal deliverability gain; not required.
|
||||
- If option (1): `Shop.support_email` column + Alembic migration (`server_default ''`)
|
||||
+ `shop-settings` form field + validation + the usual three-layer tests.
|
||||
- **Tests:** unit (`_build_from_header`, `Shop.support_email`), integration
|
||||
(shop settings save), functional (settings POST, OTP flow still works).
|
||||
- **Docs:** `docs/architecture.md` ticket index, `docs/design-system.md` if a
|
||||
new form field, `CLAUDE.md` note, portal `pricing.html`/`index.html` if
|
||||
surfaced to users.
|
||||
Loading…
Add table
Add a link
Reference in a new issue