做源码交易和转卡码平台的朋友都清楚一个痛点:用户付了钱,卡密或下载链接却要自己回到页面刷新查询,很多用户找不到入口就流失了,甚至误以为没发货而申请退款。而支付宝小程序模板消息(formId 机制)下线之后,很多人一下子不知道用什么方式在支付后主动触达用户。这篇文章就完整讲一遍 支付宝小程序订阅消息 的实战接入:从模板申请、前端授权,到后端 Python 发送、发送记录与重试,最后落地到"支付成功自动推送卡密"这个最实用的场景。
一、为什么是订阅消息:模板消息的迁移背景
早期支付宝小程序用的是模板消息,靠前端收集 formId 触发推送。随着平台对用户隐私和骚扰治理收紧,formId 机制已逐步下线,取而代之的是订阅消息(subscribe message)。订阅消息的核心变化有三点:
- 必须由用户主动点击授权才能发送,无法静默推送
- 一次授权对应一条消息(一次性订阅),发完即失效
- 发送由服务端 API 完成,前端只负责引导授权
对商城、转卡码这类"支付后发货"的场景,订阅消息反而更合适:用户在支付成功页顺手点一次授权,系统在发货瞬间把卡密推过去,触达率远高于让用户自己回访页面。
二、准备工作:开通能力与申请模板
第一步在支付宝开放平台后台完成:进入「小程序开发 → 开发设置 → 消息推送」,开通订阅消息能力,然后创建模板。注意类目要和小程序的服务类目匹配,比如电商类目才能申请"订单发货通知"类模板。申请通过后会得到一个模板 ID(entityId),形如 8f0c4f8c2c0d4f4d9c2f...,前后端都要用到。
三、前端:支付成功后引导授权
前端用 my.requestSubscribeMessage 唤起授权弹窗,把模板 ID 放进 entityIds 数组。注意这个 API 只能在用户点击事件的回调里调用,不能在页面 onLoad 里静默调用。以支付宝小程序 axml 为例:
<!-- pay-success.axml --> <view class="card"> <text>支付成功,点击领取卡密</text> <button size="default" onTap="onSubscribe">开启发货通知</button> </view>
// pay-success.js 用户点击事件回调中唤起授权 Page({ onSubscribe() { my.requestSubscribeMessage({ entityIds: ['8f0c4f8c2c0d4f4d9c2f...'], // 申请到的模板 ID success: (res) => { // res.subscribeStatus[模板ID] === 'accept' 表示授权成功 const status = res.subscribeStatus['8f0c4f8c2c0d4f4d9c2f...']; if (status === 'accept') { my.showToast({ content: '发货后将第一时间通知您' }); } }, fail: () => { // 用户拒绝也不影响下单,发货时降级为站内信/短信 console.log('user rejected subscribe'); } }); } })
这里有个容易被忽略的坑:授权状态不要只存在前端。用户授权后,要把结果上报给后端(比如随订单状态一起提交),后端发送时才知道"这条订单能不能走订阅消息"。建议在订单表上加一个 subscribe_status 字段。
四、后端:Python 发送订阅消息
后端发送走开放平台 API alipay.open.app.mini.templatemessage.subscribe,推荐直接使用官方 alipay-sdk-python,RSA2 签名、时间戳、nonce 这些细节都封装好了。安装后代码如下:
pip install alipay-sdk-python
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.request.AlipayOpenAppMiniTemplatemessageSubscribeRequest \
import AlipayOpenAppMiniTemplatemessageSubscribeRequest
# 初始化客户端:应用 ID、应用私钥、支付宝公钥、开放平台网关
client = DefaultAlipayClient(
gateway="https://openapi.alipay.com/gateway.do",
app_id="2026XXXXXXXXXXXX",
private_key=open("/path/app_private_key.pem").read(),
alipay_public_key=open("/path/alipay_public_key.pem").read(),
sign_type="RSA2",
charset="utf-8",
)
def send_subscribe_message(template_id, data, scene="order_delivery"):
req = AlipayOpenAppMiniTemplatemessageSubscribeRequest()
# biz_content:data 为模板字段名到值的映射,scene 标识业务场景
req.biz_content = {
"data": data, # 例如 {"卡密": {"value": "ABC-123-XXX"}}
"scene": scene,
}
resp = client.execute(req)
# 返回 code=10000 表示发送成功
if resp.code == "10000":
return True
# 常见失败:40004 业务校验失败 / 用户未授权 / 消息已失效
log.error("subscribe send failed: %s %s", resp.code, resp.msg)
return False
# 发货时组装模板字段并发送
ok = send_subscribe_message(
"8f0c4f8c2c0d4f4d9c2f...",
{"商品": {"value": "转卡码系统V3 完整源码"},
"卡密": {"value": order.card_no},
"提示": {"value": "请在 个人中心-我的卡密 中查看"}},
)
三个实战要点:一是 data 的字段名必须和后台模板里定义的字段完全一致,多一个少一个都会报参数校验错误;二是 code=10000 才算成功,其他返回码要进重试或降级流程;三是发送前先查一下订单的 subscribe_status,没授权的用户直接跳过,别白白浪费一次调用。
五、发送记录与失败重试
消息发送必须留痕,否则出了问题无从排查。建一张发送记录表:
CREATE TABLE subscribe_msg_log ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(64) NOT NULL COMMENT '订单号', template_id VARCHAR(64) NOT NULL COMMENT '模板ID', content JSON NOT NULL COMMENT '发送内容快照', status TINYINT NOT NULL DEFAULT 0 COMMENT '0待发送 1成功 2失败 3重试中', retry_count TINYINT NOT NULL DEFAULT 0, err_code VARCHAR(16) DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_order (order_no), KEY idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息发送记录';
发送流程建议做成先落库、后发送:发货事务里先插入一条 status=0 的记录,再由支付回调后的异步任务扫描发送,成功后更新状态。再配一个定时重试任务,每 5 分钟扫一次 status=2 且 retry_count < 3 的记录重发,就能覆盖大部分瞬时失败。
六、与转卡码系统集成:支付回调 → 自动推送
把上面几块串起来,就是转卡码平台的标准发货通知链路:支付宝异步通知(notify_url)验签通过 → 订单状态机迁移为已支付 → 生成卡密入库 → 检查用户订阅授权 → 组装模板字段发送订阅消息 → 写发送日志。核心代码如下:
# 支付回调处理(伪代码) def on_pay_notify(order): # 1. 验签 + 幂等处理(防重复通知) if not verify_alipay_notify(request.form): return "failure" if order.status == "PAID": return "success" # 2. 状态迁移 + 生成卡密 + 落库发货 card = issue_card(order) # 3. 用户授权过订阅消息就推送,否则降级为站内信 if order.subscribe_status == "accept": send_subscribe_message(TEMPLATE_ID, { "商品": {"value": order.product_name}, "卡密": {"value": card.code}, }) else: create_station_letter(order, card) return "success"
这套链路在我们的 转卡码系统 V3 里是开箱即用的:小程序端已封装授权弹窗,后端内置订阅消息发送与降级策略,支付回调、卡密生成、消息推送一条龙。如果你主要做 H5 生意,转卡码系统 V2 的站内信 + 短信通知方案同样成熟,无需小程序也能完成发货触达。
七、避坑清单
- 订阅授权必须在点击事件中唤起,onLoad/onShow 里调用会直接失败
- 一次授权 = 一条消息,发完即失效;可在"我的订单"页常驻授权入口,引导用户多次授权
- 模板字段名、类型必须与后台模板一致,否则发送报参数校验错误
- 发送结果以
code=10000为准,前端 success 回调不代表发送成功 - 授权状态要落库,前端状态不可信;用户拒绝授权时准备站内信/短信降级方案
- 不要滥用:订阅消息用于发货、售后等强相关场景,营销类内容容易触发平台处罚
八、小结
订阅消息是目前支付宝小程序里唯一合规、稳定、免费的服务端触达通道。把"支付 → 授权 → 发货 → 推送"这条链路做好,卡密领取率和复购率都能明显提升。模板申请、前端授权、后端发送、日志重试四步走完,你的小程序就能在用户付款后第一时间把货送到手里。需要现成方案的话,欢迎到 源码商城 看看转卡码系统 V3 的小程序端实现,或者用 Codex Desktop 帮你把这套代码半小时内写完。