ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信公众号模板推送全指南:服务号与订阅号的区别及实现方案

微信公众号模板推送全指南:服务号与订阅号的区别及实现方案 我做了多年公众号开发和运营发现一个特别常见的现象一提“模板推送”很多人第一反应就是把服务号和订阅号混为一谈结果权限都开通完了才发现——订阅号压根没有模板消息接口白忙一场。反过来也有人把服务号当订阅号用天天琢磨怎么发内容却不知道 4 条群发限制的帽子扣下来运营计划全部泡汤。这篇文章我打算把微信公众号模板推送这件事彻底讲透服务号和订阅号在底层接口权限上到底差在哪为什么服务号能玩模板推送、订阅号只能用订阅通知代替以及真实项目里从申请模板到调用接口再到排查各种报错的全过程。希望能帮正在做公众号自动化提醒、订单通知、活动推送的开发者或运营同学少走几趟弯路。1. 服务号和订阅号两种产品形态的本质差异很多人以为服务号和订阅号的区别只是“一个月能群发 4 次还是 1 次”这个理解太片面了。真正拉开差距的是它们的产品定位以及微信在后面赋予的接口能力。接口能力决定了你能做什么系统、能触达多深的业务场景而群发次数只是其中一个显性指标。1.1 定位不同决定了权限天花板服务号的核心定位是“为企业和组织提供更强大的业务服务与用户管理能力”所以它开放了支付、模板消息、网页授权、客服消息、门店管理等一大批高价值接口。订阅号的核心定位则是“为媒体和个人提供一种新的信息传播方式”主要解决内容分发问题接口权限被砍得相当克制。我这个说法可能还是抽象换个比喻服务号更像一个“营业厅”用户可以来办业务、收通知、查状态订阅号更像一个“报刊亭”只能被动的把报纸递给路过的人。营业厅需要大量后台系统支撑所以微信给了足够多的钥匙报刊亭只需要发传单微信自然不给你开库房的门。这就是为什么你做“订单发货提醒”“预约成功通知”“余额变动告警”这类功能必须放在服务号上。订阅号就算头像挂得再漂亮也没有对应的接口能力这属于产品形态层面的硬限制。1.2 接口权限的矛盾点谁有模板消息我整理过一份开发时最常遇到的权限对比发出来供参考能力维度服务号订阅号个人订阅号模板消息支持需类目和模板审核不支持原生模板消息不支持订阅通知支持一次性/长期支持一次性订阅为主支持客服消息支持48小时窗口期支持48小时窗口期支持网页授权支持静默和用户信息不支持高级授权不支持微信支付支持不支持不支持自定义菜单支持支持支持群发次数每月4次每天1次每天1次能看到模板消息是服务号专属的“硬核能力”订阅号只能通过订阅通知曲线救国。这里说的订阅通知很多人也叫它“一次订阅一次推送”用户主动点了订阅按钮之后你才能在特定时间或事件发生时推一条且订阅行为本身就是用户明确的授权动作而不是像服务号模板消息那样——只要用户触发过某个事件就满足发送条件。1.3 消息触达能力决定了推送策略做过运营的都清楚在微信生态里用户根本不会天天点开你的公众号。如果你的提醒类信息只能躺在列表里等用户“宠幸”那基本等于白推。服务号模板消息可以直接出现在用户的会话列表像收到一条微信聊天一样打开率比群发图文高出一个量级。而订阅号即使每天群发 1 次最终能触达多少人也取决于用户是否订阅、是否把公众号置顶、是否打开了通知。所以我在给客户做方案时第一步永远是确认公众号主体和类型如果是新注册我会直接建议企业主体注册服务号别在订阅号上硬拗提醒场景。不然功能开发到一半发现没有模板消息权限再改号等于推倒重来那个成本谁都扛不住。2. 模板消息不是“随便推”的通知背后是一整套规则模板消息看着就是往用户微信里塞一条通知但微信对它有一套非常严格的约束机制。这一节把模板消息的核心原理和边界规则拆开讲。2.1 模板消息到底解决什么问题模板消息设计的初衷是解决“服务号无法主动把业务流程状态同步给用户”的问题。比如你在小程序里下单了商家发货后需要告诉你快递单号你在医院公众号挂了号到号了提醒你去看诊你信用卡还款日到了银行提醒你别忘还。这些消息的共同点是都发生在一次真实业务动作之后用户对消息有预期消息本身也有明确的结构。微信模板消息用“模板 字段”的形式来承载模板规定标题、行业、内容结构字段由开发者动态填充。模板消息的优势很明显不占每月群发次数模板消息走单独接口和群发图文互不影响。展示层级高出现在会话列表点开就能看。结构标准开发者和用户都对消息内容格式有稳定预期。可以跳转网页或小程序模板消息支持配置跳转链接实现从提醒到业务的闭环。但这里有个隐藏的坑模板消息不是营销工具不能像群发那样随便发广告。如果频繁给用户发送无业务价值的消息轻则被用户投诉重则被限制模板消息接口甚至封号。2.2 模板消息的申请和使用规则模板消息的使用分两步先申请模板再调用接口发送。申请模板时的核心约束行业类目必须匹配公众号后台需要先设置行业类目申请的模板也必须属于对应行业。比如你做电商却申请了一个“医疗就诊提醒”模板审核大概率被驳回。模板标题和内容不能自定义你只能从微信官方模板库里选择不能自己杜撰标题和字段。关键词颜色也有讲究模板消息里的内容可以设置颜色但微信建议使用默认黑色花花绿绿的通知会严重影响阅读体验也更容易触发风控。有并发上限和频控同一模板有日调用上限接口本身也有频控策略具体阈值和账号权重挂钩新号通常比较严格。发送时的核心规则用户必须先“触发”一次动作模板消息的发送前提是用户最近 48 小时内与公众号产生了交互比如点击菜单、回复关键字、扫码等。超过 48 小时没有交互就无法发送。不能通过模板消息诱导分享模板消息里不能出现诱导转发、诱导关注的字样否则随时可能被封模板接口。跳转链接必须是安全域名设置的网页跳转 URL 需要提前配置 JS 接口安全域名并在公众号后台完成校验否则跳转会失败。2.3 模板消息 vs. 订阅通知 vs. 客服消息很多新手把这三者搞混我在这里做一次彻底区分。模板消息的主干逻辑是“业务事件驱动”用户和你的业务系统发生过交互后你在窗口期内把结果状态推给他。比如用户下单交互动作- 订单状态变化业务事件- 推送“订单发货通知”模板消息。订阅通知的逻辑是“用户主动订阅一次获得一次推送机会”。它在小程序里很常见用户点一个“订阅”按钮授权后你才能在某次预期事件发生时推消息。公众号里的普通订阅号没有模板消息但可以做订阅通知只是无法像服务号那样无感触发。客服消息则更特殊它是“48 小时会话窗口”内的双向沟通能力。用户主动给公众号发消息后公众号就获得了 48 小时内回复客服消息的权利。客服消息支持文本、图片、图文、小程序卡片等丰富格式但依赖用户先主动开口所以适合做“自动回复机器人”和人工客服不适合做状态提醒。实操中我经常把这三者组合用客服消息做用户咨询的自动应答模板消息做交易状态的主动通知订阅通知用于获取新用户的推送授权。三者各管一段互不干扰。3. 服务号实操把模板推送真正跑通前面讲了这么多原理这一节进入正题手把手教你在服务号上完成一次真实的模板消息推送。我以最常见的“订单发货通知”为例从后台配置到代码实现全部走一遍。3.1 后台配置类目、模板库与安全域名先在微信公众平台登录你的服务号左侧菜单找到“设置与开发 - 接口设置”或“功能 - 模板消息”。不同时期后台版本有差异但核心入口基本都在“功能”或“设置”里。第一步是确定行业类目。进入“公众号设置 - 服务类目”选择与你业务匹配的行业。比如电商类选“电商平台/百货/超市”医疗类选“医疗”教育类选“教育”。类目选错后面申请模板时大概率被系统直接拒绝。第二步是申请模板。进入模板消息页面点“从模板库中添加”选择“订单发货通知”相关的标题。你可以通过搜索关键词来找每个模板后面会标注适用类目、字段数量、字段名称。选中后确认系统会自动生成一个模板 ID类似OPENTM1234567890这个就是后续调用接口要用的关键参数。第三步是配置跳转域名。如果你的模板消息要带上链接需要在“设置与开发 - 公众号设置 - 功能设置”里配置 JS 接口安全域名。注意域名必须备案并且需要在根目录放一个微信验证文件完成归属校验。3.2 获取 access_token并处理缓存几乎调用微信所有业务接口前都需要先获取一个全局凭据就是 access_token。它每天有获取次数限制默认 2000 次所以绝对不能每次发消息都去拉一次必须缓存起来。获取 access_token 的接口地址是GET https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credentialappidAPPIDsecretAPPSECRET返回结果里有一个access_token和expires_in有效期通常是 7200 秒。我做项目时的做法是在服务器内存里做一个定时刷新任务或者存 Redis用过期时间提前 5 分钟主动刷新。这样既不超频又能保证拿到的 token 一直是新鲜的。这里有一个特别容易踩的坑如果把 access_token 暴露到前端页面用户或爬虫拿到你的appid secret理论上可以冒充你的服务器调用接口。所以我建议所有 token 逻辑一律放在后端前端只传 openid 和业务参数。还有不要用 GET 请求带 secret 的完整 URL 去调试尤其不要贴到公开的代码仓库里。3.3 构建模板消息体模板消息的请求地址是POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_tokenACCESS_TOKEN请求体结构如下{ touser: OPENID, template_id: TEMPLATE_ID, url: http://yourdomain.com/order/detail/123, data: { first: { value: 您的订单已发货, color: #173177 }, keyword1: { value: JD1234567890, color: #173177 }, keyword2: { value: 顺丰速运, color: #173177 }, keyword3: { value: SF1234567890, color: #173177 }, remark: { value: 请保持电话畅通及时取件。, color: #173177 } } }这里的字段名比如keyword1、keyword2必须严格对应你在后台申请模板时定义的字段顺序和名称。如果后台模板里第二个字段是“快递公司”你却把快递单号填进去了用户收到的消息就会驴唇不对马嘴。first和remark是模板消息的开头和结尾一般用来写摘要和补充说明。url是用户点击消息后跳转的地址不填则点击无跳转。touser是用户的 openid不是微信号也不是手机号只能通过用户关注或网页授权后换取。3.4 完整 Python 示例我平时主要用 Python 写后端逻辑这里给出一段可以直接跑的代码逻辑包括获取 token带缓存、发送模板消息、统一异常处理。import json import time import requests class WechatTemplateSender: def __init__(self, appid, secret): self.appid appid self.secret secret self.token None self.token_expires_at 0 def _refresh_token(self): url https://api.weixin.qq.com/cgi-bin/token params { grant_type: client_credential, appid: self.appid, secret: self.secret } resp requests.get(url, paramsparams, timeout10).json() if access_token not in resp: raise RuntimeError(f获取token失败: {resp}) self.token resp[access_token] self.token_expires_at time.time() int(resp[expires_in]) - 300 def _get_token(self): if not self.token or time.time() self.token_expires_at: self._refresh_token() return self.token def send_template(self, openid, template_id, data, urlNone): token self._get_token() api fhttps://api.weixin.qq.com/cgi-bin/message/template/send?access_token{token} body { touser: openid, template_id: template_id, data: data } if url: body[url] url resp requests.post(api, jsonbody, timeout10).json() if resp.get(errcode) ! 0: raise RuntimeError(f发送模板消息失败: {resp}) return resp if __name__ __main__: sender WechatTemplateSender(your-appid, your-secret) data { first: {value: 您的订单已发货}, keyword1: {value: JD1234567890}, keyword2: {value: 顺丰速运}, keyword3: {value: SF1234567890}, remark: {value: 请保持电话畅通及时取件。} } sender.send_template(USER_OPENID, TEMPLATE_ID, data, https://yourdomain.com/order/123)代码逻辑很简单但有几个细节值得注意timeout必须加否则微信接口若挂起你的服务线程会被拖死。token 刷新时间比实际有效提前 5 分钟避免临界点请求失败。每次返回都要检查errcode微信接口返回 0 才是成功不要只判断 HTTP 200。发送接口的 token 如果失效会返回40001此时应该主动刷新 token 并重试一次而不是把错误直接抛给用户。4. 订阅号没有模板消息怎么实现“提醒类”推送我知道一定有同学正在用订阅号看完上一节大受震撼模板消息根本没权限怎么办别慌订阅号并不是完全没路可走只是要换一套打法。4.1 用测试号练手接口体验与联调如果你还没有服务号但想先试试模板消息的 API 流程可以去微信公众平台申请一个“接口测试号”。测试号不需要企业资质不需要认证申请后直接获得几乎所有接口权限包括模板消息。测试号入口通常在“开发 - 开发者工具 - 公众平台测试号”登录后它会给你一个测试用的 appid 和 secret以及一个测试模板库。这里的模板消息申请是即时生效的不用等审核。我用测试号做过好几轮联调非常适合三种场景前端还没上线先用测试号把消息发送闭环跑通。需要给团队成员演示效果又不想动生产环境模板。验证字段格式、URL 跳转、小程序跳转等逻辑是否有 bug。不过要强调测试号里获取的 openid 和生产环境的 openid 不通用。测试号的用户管理是独立的你需要先让参与测试的微信号关注测试号才能拿到对应的 openid。4.2 订阅通知订阅号的正规替代方案订阅号没有模板消息但微信给订阅号开放了“订阅通知”能力。用户在公众号内主动点击“订阅”按钮后开发者可以向用户发送一条订阅通知。订阅通知的使用流程在公众号后台申请开通订阅通知功能。从订阅通知模板库中申请模板。前端页面公众号网页或图文内里放置订阅按钮调用相关接口引导用户授权订阅。当用户完成订阅后在业务事件发生时调用接口发送订阅通知。订阅通知和模板消息的关键差别就是“用户必须先主动订阅”。这个订阅动作让订阅号只能用“诱饵式”的推送方式——比如在公众号图文里放一个“开奖提醒”按钮用户订阅后到了开奖时间再推给他一条结果通知。实操中我发现订阅通知有一个比较尴尬的点用户订阅一次只能获得一次推送机会如果推送失败或者用户没点开机会就浪费了。所以做订阅通知时一定要把“订阅”按钮做成明确、可信、可复用的最好在订阅时告诉用户“你会收到哪些消息大概什么频率”降低用户的反感度。4.3 客服消息、自动发文等实用思路订阅号做提醒类推送还有几个组合拳思路。客服消息是最容易忽略的用户在会话窗口给订阅号发一条消息不管发的是“订单”“帮助”还是“在吗”你都能在 48 小时内以客服消息格式回复一条结构化内容。这意味着你可以在公众号菜单或自动回复里引导用户输入关键词比如“查订单”然后自动回复里带上订单状态、物流信息。这种方式的体验虽然没有模板消息那么“主动”但胜在不需要订阅通知的一次性授权而且可以回复的内容种类更多支持图文、小程序卡片、语音等。很多订阅号就是把客服消息做成了“伪查询系统”。自动发文也是订阅号的重要玩法。通过微信后台的“图文消息”接口或第三方排版工具可以在每天固定时间自动发送推文。虽然它不是模板消息但对于内容型订阅号来说固定频次的自动发文才是主力触达工具模板推送只能作为辅助提醒。要留意的是自动发文要严格遵守平台运营规则不能发灰产、营销垃圾信息否则很容易触发平台风控。还可以考虑 RPA 方案在订阅号上通过 RPA 机器人模拟用户操作自动完成发文、回复评论、同步数据等动作。这种方式适合不想碰代码的运营同学但 RPA 的稳定性始终不如官方 API尤其是微信前端界面一旦改版RPA 流程就要跟着调整。建议 RPA 只用来做低风险、可重试的辅助操作核心业务还是交给官方接口。4.4 选型建议什么场景用什么号我把这些年见到的公开场景整理成一张决策表大家可以直接对号入座业务场景推荐号型方案说明电商订单、物流状态通知服务号模板消息业务事件驱动体验最好预约成功/就诊提醒服务号模板消息 微信支付完整闭环会员积分变动提醒服务号模板消息字段丰富可跳转会员中心内容日更 开奖提醒订阅号图文自动发文 订阅通知客服咨询自动回复服务号/订阅号均可客服消息重点做菜单引导和关键词识别内部办公通知企业微信更合适公众号不适合做员工内网通知养成类签到/打卡提醒服务号模板消息 网页授权带用户身份识别如果业务刚起步、预算有限也可以先用订阅号做内容验证等用户量起来了再注册服务号重点做触达转化。但是注意一旦业务模型明确需要模板消息别犹豫尽早切换。公众号迁移和粉丝迁移虽然能做但成本不低。5. 高频问题排查实录这一节是纯实战经验我把做模板推送时踩过的高频坑和排查方法完整整理一遍基本覆盖大多数开发者的日常问题。5.1 模板ID失效和类目不匹配表现调用接口返回errCode: 40037提示 template_id 不正确。排查思路模板 ID 不是随便填的必须从你公众号后台的模板消息页面复制。如果从网上抄了一段模板 ID大概率不是你这个号申请过的直接报错。还有一种情况是模板申请时换了行业类目导致原来的模板变成“停用”状态此时 ID 也会失效。注意模板消息接口的行业类目一旦确定每年只有极少数次数可以修改所以注册后先想清楚主营类目不要因为着急测试随便选后续再改成本很高。解决进入“模板消息”页面删除旧模板重新从模板库添加一个同标题模板把新的 template_id 更新到代码配置中。5.2 字段不匹配和格式异常表现接口返回errCode: 47003或者消息成功发出但用户看到的内容和预期不一致。排查思路47003 的意思是参数不正确常见原因是 data 里的 keyword 数量和顺序与模板定义不一致。举例模板定义了keyword1为物流公司、keyword2为运单号你却在keyword1里传了一个电话号系统不会拦截但用户收到的通知就是乱的。解决把后台模板详情展开逐字段对照代码中的 data 映射关系。字段值除了字符串某些模板还要求具体格式比如金额类字段只允许数字和小数点日期类字段必须是标准时间格式。5.3 用户接收不到消息表现接口返回成功errcode: 0但用户什么都没收到。排查思路这种情况最迷但也最好排查按顺序检查这几个点用户是否取关了公众号取关后接口可能依旧返回成功但消息不会展示。用户最近 48 小时是否与公众号有过交互模板消息需要一次有效的“用户触发”动作比如点击菜单、回复消息、扫码。如果用户只是被动关注超过 48 小时不发一条模板消息。用户是否在微信设置里关掉了“接收文章推送”或“消息通知”这是用户侧开关你无法通过接口强制打开。是否在发送前更换过 openid不同公众号、测试号、小程序之间的 openid 不通用换环境后必须重新获取。解决打开微信公众平台后台的“消息发送记录”查看这条消息的状态。如果状态是“已送达”那就是用户侧问题只能引导用户在设置里检查通知开关。如果状态是“失败”根据错误码继续排查。5.4 频率限制和 45009 接口并发超限表现接口返回45009表示接口调用超过频控上限。排查思路模板消息接口的频控是分维度的同一个模板单日调用量、单用户单日接收模板消息条数、整个公众号日调用总量。不同维度的阈值和账号历史表现挂钩。解决线上环境要做消息队列把模板消息发送逻辑串行化同时做告警监控。如果业务需要大量发送建议分时段批量发而不是集中在某几分钟内打满否则会被微信临时限制。对高频业务比如签到提醒可以改成合并消息把用户一天内的多条通知合并成一条模板消息既降低频控风险又减少对用户的打扰。5.5 链接无法跳转或提示非安全域名表现用户点击模板消息打开后提示“无法访问”或者“网络出错”。排查思路模板消息里配置的url必须是你自己的域名且域名需要完成 ICP 备案。如果链接是外链或者未备案域名微信直接拦截。解决确认域名已备案并在公众号后台配置了 JS 接口安全域名。还有一点URL 必须完整带https://前缀不带则是非法链接。如果跳转目标是小程序则不用配置 url改配置miniprogram参数并确保小程序和公众号是同一主体且已完成关联。6. 开发与运营层面的额外心得最后再补充几条我做了多年公众号消息系统的个人体会不算教程更像是在项目里沉淀下来的经验。第一模板消息一定要设计“降级预案”。线上系统复杂微信接口偶尔会抖动用户也可能会关闭通知。重要业务的通知不能全押在微信这一条链路上建议同时对接收信短信或站内信。我在发货通知这个场景里就做了模板消息为主、短信兜底的策略虽然成本高一点但用户体验稳得住。第二模板消息的文案要克制、要明确。模板的first和remark是你唯一能自由发挥的空间写“您的订单已发货请及时查看物流信息”就比写“尊敬的用户您好感谢您选择我们您的订单我们已经处理啦”强得多。用户看消息是为了解决问题不是为了感受热情。第三做好消息内容的埋点。微信的模板消息点击数据在公众平台后台只能看到很粗粒度的数据我自己会在跳转 URL 上加上 event 参数和用户 openid这样点击率、转化率都能落到自己的数据分析系统里。比如url写成https://yourdomain.com/order/123?utm_sourcetemplateopenidxxx后续做漏斗分析时就知道有多少用户从模板消息点进来了。第四模板库里的模板不值得花太多时间“寻找完美”。很多人喜欢纠结要选哪个模板、哪个字段排序其实用户根本不会仔细看字段排序他们只关心这条消息告诉了我什么、下一步该做什么。选一个结构清晰、字段切题的模板比反复比较哪个模板更高大上重要得多。如果后续想做更复杂的场景比如在模板消息里携带小程序卡片跳转到订单页或者在客服消息里嵌入带参二维码方法和本文的框架完全一致只是把对应接口替换掉。公众号消息推送这套体系只要把服务号/订阅号的产品差异、模板消息的规则约束、接口调用的细节嚼透后面无论换什么业务场景都能稳稳接住。
返回列表