做公众号开发和运营的朋友,一定遇到过“模板推送”这个绕不开的需求:订单提醒、审核结果、活动通知、课程开课提醒,都需要精准地塞进用户的微信会话里。但一搜教程,满屏都是“服务号能发模板消息、订阅号不能”的结论,然后就没有下文了。实际情况要复杂不少——认证订阅号也能接模板消息,只是权限边界、申请入口、触达位置跟服务号完全不在一个量级,而且2020年以后微信对模板消息、通知类消息做过多次调整,很多老教程的代码跑起来全是坑。这篇内容我按照自己实际跑过的项目来写,把服务号和订阅号在模板推送这件事上的差异、操作链路、替代方案、常见翻车点一次讲透,适合正在做公众号消息推送的运营、前后端开发,以及准备选型账号类型的产品经理参考。
1. 权限底册:服务号与订阅号在模板推送上的天然差异
1.1 三类账号的“出生配置”
微信公众平台现在基本把公众号分成订阅号、服务号、企业号(企业微信相关)三大类,日常做模板推送主要涉及订阅号和服务号。这里有一个很常见的误区:很多人以为“个人订阅号 = 订阅号”,实际上订阅号又分个人主体和企业/组织主体,服务号则必须是企业、政府、媒体等组织主体才能注册。
个人主体订阅号没有模板消息接口权限,这是最硬的一条天花板。如果你只是注册了一个个人公众号,想在后台找“模板消息”入口,大概率是找不到的。认证的企业订阅号则具备模板消息接口,但消息会折叠进“订阅号消息”文件夹里,用户打开率、触达率天然比服务号低。而服务号一旦完成微信认证,模板消息就是标准配置,消息直接落到聊天列表的会话卡片里,触达效果好得多。
这三者差别,本质上是微信对“打扰程度”的分级管理。服务号一个月只能群发4次,但消息直接置顶在用户聊天列表;订阅号可以每天群发一次,但被折叠起来;模板消息则属于“服务通知”性质,不占群发次数,但要求它必须由用户行为触发或符合特定服务场景,不允许拿来当营销工具群发。
1.2 认证状态才是真正的分水岭
如果你已经有一个企业订阅号,但没认证,模板消息还是用不了。微信的接口权限体系里,认证是一次全面解锁,只有完成微信认证(每年300元那个),订阅号才能拿到部分高级接口,包括模板消息、客服消息、网页授权等。
服务号也一样。虽然服务号本身支持模板消息,但未认证的服务号在接口权限上会被打折扣,很多关键接口用不了。所以选型时不要只看“服务号 vs 订阅号”,第一优先级是确认主体资质和认证状态。以我接触过的不少项目为例,客户拿着一个没认证的订阅号说要接模板消息,开发到一半发现接口返回“48001 api unauthorized”,然后整个排期被打乱,只能紧急去补认证流程。
这里补充一个实操建议:如果你只是想早点跑通模板消息的开发和联调,可以先去微信公众平台的“测试号”页面申请一个测试号。测试号不需要认证,也不需要企业资质,就能体验模板消息、素材管理、自定义菜单等几乎全套接口能力,开发阶段拿它调试完全够用。等正式号认证下来,再把测试号里调好的逻辑迁移过去,基本无痛。
1.3 模板消息的本质:它到底适合发什么
模板消息不是让你随便给用户发广告的。微信对它的定位是“服务通知”,适合的场景包括:交易状态变化(订单发货、退款成功)、账号状态变化(审核通过、密码修改)、预约提醒(就诊时间、课程开课)、物流信息、会员积分变动等。
这些场景有几个共同特征:时效性较强、内容结构固定、由用户操作或平台事件触发、对用户有实际价值。模板消息的消息体由固定字段构成,运营者只能往字段里填值,不能像图文消息那样自由排版,这既是限制也是安全边界——正因为内容被结构化,用户才不会收到又臭又长的营销广告。
我在实际项目里见过最典型的违规是:把模板消息当成群发工具,向所有历史用户批量推送促销信息。这种情况很容易被平台判定为滥用,轻则接口被限流,重则封禁模板消息能力,甚至影响整个公众号的正常使用。所以从设计阶段就要想清楚:你的模板消息是为了解决用户的什么真实需求,而不是为了完成你的KPI。
2. 开通模板消息的第一步:类目、模板库和模板ID的申请细节
2.1 后台入口和类目选择
这里先说明,订阅号是否能在后台看到模板消息入口,取决于认证状态。认证服务号/订阅号登录公众平台后,左侧菜单“功能”或“广告与服务”区域一般会有“模板消息”入口,点进去会看到“模板库”和“我的模板”两个主要板块。
第一次使用时,系统会要求你先选择行业类目,因为模板库里的模板是按照行业分类的。类目选错,后面申请模板时就会发现可用的模板少得可怜,或者关键词完全对不上。常见的类目组合是“主营行业 + 辅助行业”,比如你做一个电商平台,主营行业选“电商平台”,辅助行业可以选“IT科技”或“生活服务”。
这里有一个小技巧:类目选定后不是不能改,但改起来比较折腾,而且会影响已选模板的使用状态。所以在选类目前,先把你的业务核心场景列出来,比如“订单通知”“物流通知”“售后通知”,然后去对应类目下搜一下模板关键词,确认能找到合适模板再锁定类目。不要拍脑袋选,否则后面只能通过“新增类目”方式弥补,审核周期又得好几天。
2.2 关键词匹配与模板选择技巧
类目确定后,就可以在模板库搜索框里搜关键词了,比如搜“订单”“发货”“提醒”“审核”。每个模板都会展示标题、内容字段、适用场景,有的模板还标明申请数量限制。
选择模板时要重点看两个东西:字段名和字段数量。模板消息的内容由“first”“keyword1、keyword2……”“remark”之类的字段构成,每个字段对应一段文本。你要评估的是:这个模板的字段数量够不够装下你的业务信息。比如你做的是外卖平台,想推送“订单已送达”+“骑手联系方式”+“配送时长”,如果选了一个只有两个keyword的模板,就很难塞下完整信息。
另一个点是模板的“标题”和“业务含义”要贴合。微信审核模板时比较关注标题与实际推送内容的一致性,有些供应商会准备一批备选模板,申请时如果标题和类目不吻合,审核会拒。我的经验是:先用后台搜索功能多找3到5个备选模板,把标题、字段数量、字段名称排个对比表,再选综合匹配度最高的那个,不要只盯着一个模板死磕。
2.3 服务号和订阅号申请流程的差异点
申请流程本身差别不大,但有几个隐性差异会造成体验差异。
第一,服务号的审核优先级和审核通道,实操中感觉比订阅号更顺畅。服务号毕竟是企业核心主体,微信对它的资质审核更严格,但模板申请的审核速度通常也比较快;订阅号如果主体类型是个人升级来的或者主体信息不完整,模板申请容易卡在类目与内容不匹配上。
第二,订阅号在后台提交模板后,即使审核通过了,也需要在代码里调用接口获取模板ID。服务号一样,但服务号可以额外在后台直接给指定用户下发测试模板消息,订阅号往往没有这个按钮或功能入口,只能调试接口来验证。
第三,服务号的模板消息可以设置“跳转小程序”,订阅号模板消息在部分场景下跳转能力受限或配置路径不同。如果你的业务需要从模板消息点击后直接打开小程序某个页面,这一点要提前确认清楚,别等开发完才发现订阅号的消息卡片跳不了你的小程序。
3. 服务号实操:后台配置、接口调用和完整代码示例
3.1 后台配置:复制模板ID、设置跳转路径
服务号通过模板申请后,在“我的模板”里能看到一个长字符串,那就是 template_id,也是每次接口调用必须要用到的参数。它相当于模板的“身份证”,不同模板对应不同内容结构,发送接口靠它识别要下发的内容格式。
这里还要配置接收方的身份标识。公众号体系里,每个用户在不同公众号下面有唯一一个 openid,发送模板消息时以 openid 作为 touser 参数。获取用户 openid 的常见方式是通过网页授权(snsapi_base 静默授权)或者用户关注公众号后的事件推送里拿。要注意:同一个微信用户在你不同公众号下的 openid 是不同的,服务号拿到的 openid 不能用在订阅号接口上,这个坑下面会单独说。
跳转链接(url)和跳转小程序(miniprogram)都在调用接口时动态传入,不需要在后台配置死。如果你的模板消息需要带用户进入指定页面,可以在发送时把 url 设成带参数的地址,或者设置 miniprogram 参数指定小程序 appid 和页面路径。
3.2 接口调用的完整链路
公众号模板消息的核心接口是POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN,请求体大概长这样:
{ "touser": "OPENID", "template_id": "TEMPLATE_ID", "url": "https://yourdomain.com/order/detail?id=123", "miniprogram": { "appid": "小程序APPID", "pagepath": "pages/order/detail?id=123" }, "data": { "first": { "value": "您的订单已发货", "color": "#173177" }, "keyword1": { "value": "DD202501011234" }, "keyword2": { "value": "顺丰速运" }, "keyword3": { "value": "SF1234567890" }, "remark": { "value": "感谢您的购买,请保持电话畅通。" } } }调用前必须先拿到 access_token,获取方式是通过 appid + secret 调用https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET。
access_token 的有效期是7200秒,也就是2小时。千万不要每次发消息都重新拉取一次 token,否则很容易触发接口频率限制。正确做法是把 token 缓存起来,失效前再刷新。正规一点的做法是用 Redis 存 token,设置 7000 秒过期时间,在过期前主动刷新。
3.3 Python发送模板消息示例
下面是我在一个电商项目中用过的 Python 示例,逻辑很直白,关键点都做了注释:
import requests import time APPID = "your_appid" SECRET = "your_secret" TEMPLATE_ID = "your_template_id" # 获取 access_token,这里演示简单缓存方式,生产环境建议用 Redis def get_access_token(): # 先从本地缓存读取,缓存不存在或过期才去请求微信接口 try: with open("token_cache.txt", "r") as f: token, expire_time = f.read().strip().split("|") if float(expire_time) > time.time(): return token except FileNotFoundError: pass url = "https://api.weixin.qq.com/cgi-bin/token" params = { "grant_type": "client_credential", "appid": APPID, "secret": SECRET, } resp = requests.get(url, params=params).json() token = resp["access_token"] # 有效期 7200 秒,这里按 7000 秒保存,预留缓冲时间 with open("token_cache.txt", "w") as f: f.write(f"{token}|{time.time() + 7000}") return token def send_template_message(openid, data, url=None, miniprogram=None): token = get_access_token() send_url = "https://api.weixin.qq.com/cgi-bin/message/template/send" payload = { "touser": openid, "template_id": TEMPLATE_ID, "data": data, } if url: payload["url"] = url if miniprogram: payload["miniprogram"] = miniprogram resp = requests.post( f"{send_url}?access_token={token}", json=payload, timeout=10 ) result = resp.json() if result.get("errcode") == 0: print("模板消息发送成功") else: print(f"发送失败: {result}") return result if __name__ == "__main__": send_template_message( openid="oXXXXXXX", data={ "first": {"value": "您的订单已发货"}, "keyword1": {"value": "DD202501011234"}, "keyword2": {"value": "顺丰速运"}, "keyword3": {"value": "SF1234567890"}, "remark": {"value": "感谢您的购买,请保持电话畅通。"} }, url="https://yourdomain.com/order/detail?id=123" )这段代码跑通后,你会收到微信接口返回的errcode: 0。如果返回非0,常见错误码后面会单独列一个排查表。
4. 订阅号的消息能力:模板消息之外的替代路径
4.1 认证订阅号的模板消息:能用但很憋屈
很多人不知道认证订阅号其实也能申请模板消息,所以一看到自己的订阅号没权限就急着去注册服务号,白白等了主体资质审核那几天。实际上,认证订阅号可以走类似的模板申请流程,也能调用message/template/send接口下发消息。
但憋屈的点在于:订阅号所有消息,包括模板消息,默认都会收进“订阅号消息”文件夹。用户如果不把某个订阅号设为“置顶”,他根本不会第一时间看到你的模板通知——打开率断崖式下降是必然的。我曾经给一个教育培训客户的认证订阅号做过开课提醒,后台数据反馈触达量不差,但点击量就是上不去,后来发现大部分用户根本没点开订阅号消息文件夹。
所以我的建议是:如果核心业务依赖模板推送带来即时反馈(比如预约提醒、验证码类通知、订单状态变更),别用订阅号做主通道,它只适合做辅助触达。
4.2 客服消息:48小时窗口内的精准触达
订阅号虽然没有服务号那么强的模板消息触达体验,但有另一个可用的消息通道:客服消息。用户主动跟公众号互动(发消息、点击菜单)后的48小时内,公众号可以向用户下发客服消息,消息内容可以是文本、图片、图文链接、小程序卡片等。
客服消息的接口是POST /cgi-bin/message/custom/send,同样需要 access_token,传入 openid 和 msgtype。它的优势是内容形式更自由,不只限于结构化模板;劣势是48小时时间窗口限制明显,过了窗口期就不能主动发。
实操中,很多订阅号运营者会把“客服消息”做成一种“伪模板推送”:用户在小程序里触发某操作后,引导他去公众号回复关键词,然后利用客服消息窗口下发富文本通知。这个方案能规避模板消息的权限限制,但用户操作链路变长,需要产品设计上做权衡。
4.3 群发消息和内容运营:订阅号的基础牌
订阅号最大的日常武器还是每天一次的群发机会。很多人把模板消息和群发消息搞混,其实它们有很大区别:群发消息是群发素材(图文、视频、音频等),用户看到的是完整的公众号推送内容;模板消息是结构化通知,没有排版自由度。
如果你的业务以内容分发为主,日常更新量很大,那订阅号每天一次的群发权限反而是优势——可以高频触达用户,只是触达位置在“订阅号消息”文件夹里。服务号虽然触达位置好,但一个月只能群发4次,做内容日更根本不够用。
我见过不少公众号矩阵的做法是:服务号做交易提醒和重大通知,订阅号做日常内容和活动预告,两者之间通过关联引导双向导流。订阅号文章里引导用户关注服务号,服务号的模板消息里偶尔带上订阅号的内容链接,形成互补,这个组合拳比单独押注一个号要稳得多。
5. 两套账号的触达能力对比:频率、展示、转化率
5.1 消息落位差异:聊天列表 vs 折叠文件夹
服务号和订阅号模板消息最直观的差异就是消息出现在用户微信的哪里。服务号模板消息直接以会话卡片形式出现在聊天列表,用户点开就能看到完整内容;订阅号模板消息则被收进订阅号消息文件夹,用户需要额外一步点击才能看到。
这个差异对转化率影响极其巨大。自己做的实验数据里,服务号模板消息的点击率普遍在10%到25%之间(取决于通知内容的相关性),而订阅号模板消息的点击率经常在5%以下。做短信和推送的人都知道,每多一步用户操作,流失率就增加一大截,订阅号那“多一步点击”就是致命的漏斗损失。
5.2 频率与频控差异
服务号模板消息在接口层有频控限制,同一个用户、同一个模板在单位时间内的下发量有限制。虽然模板消息不占每月4次的群发额度,但接口层面防滥用机制很明显,如果短时间内对同一用户下发过多模板消息,会直接报错。
订阅号的模板消息同样存在频控。实操中我更重视“用户体感”层面的频控:即使接口允许,也不能因为能发就一直发。模板消息一旦让用户觉得是打扰,他大概率会直接取消关注,这个损失订阅号和服务号都扛不住。
这里列一个方便参考的差异表:
| 维度 | 服务号 | 认证订阅号 | 个人订阅号 |
|---|---|---|---|
| 模板消息权限 | 支持(认证后完整) | 支持(接口可用) | 不支持 |
| 消息展示位置 | 聊天列表 | 订阅号消息文件夹 | 无 |
| 群发频率 | 每月4次 | 每天1次 | 每天1次 |
| 认证要求 | 必须企业主体认证 | 必须企业主体认证 | 无法认证 |
| 适合核心通知 | 适合 | 勉强 | 完全不适合 |
| 适合内容分发 | 一般 | 适合 | 适合 |
5.3 用户感知与取关风险
服务号模板消息的“打扰感”其实比很多人想象的低,因为在聊天列表里它跟普通好友消息混在一起,用户不觉得是营销推送。而且很多服务号模板消息都配合小程序使用,用户点击后直接跳转到业务页面,整个闭环比较顺畅,取关率相对可控。
订阅号因为内容都在订阅号文件夹里,用户取关成本更低,看到一条不感兴趣的内容,顺手就取关了。所以订阅号做模板消息要更加克制:只发真正有价值、用户主动期待的通知,把频率压到最低,文案里的营销词尽量砍掉,让用户形成“这个号发的都是跟我相关的重要信息”的认知。
我在实际运营中还有一个观察:模板消息的内容结构对取关率影响比想象中大。同样的通知内容,把“first”字段写成“您的订单已发货”比写成“【XX商城】您的订单已发货,点击查看物流”的取关率低得多。模板消息不是短信营销,不需要在开头加品牌前缀,越像“系统通知”越安全,用户越不会反感。
6. 模板推送踩坑实录:6个真实问题与排查过程
6.1 access_token 过期导致的消息丢失
这是我见过最多人踩的坑。很多项目把 token 直接写死,或者每次发送都重新请求 token,前者过了2小时就失效,后者则频繁触发接口限流。我接手过一个项目,生产环境半夜报错,原因是 token 写死在配置文件里,过了2小时后所有模板消息发送失败,而且因为没人注意到日志,整整损失了半夜的通知触达。
排查链路建议:先看错误码,40001或者42001都跟 token 相关,前者是 token 无效或过期,后者是 token 过期。定位到问题后,必须用带过期时间的缓存方案,不能偷懒。
6.2 模板字段不匹配的“参数错误”
模板消息的 data 字段非常严格,多传一个字段、少传一个字段、字段类型不对,都会报错。常见错误是47003,提示 argument invalid。意思是 data 里的某个字段跟模板后台定义的不一致。
我之前遇到过一个诡异的情况:模板申请时看到的是5个 keyword,写代码时只传了3个,本地测试一直报错,后来我去后台重新查看了模板详情,才发现模板在审核期间被微信调整过字段数量。排查这类问题的方法很简单:每次调用前先从后台复制模板示例JSON,严格按示例结构改数据,不要自己发挥。
6.3 openid 跨账号混用
用户在不同公众号、小程序下的 openid 是完全不同的。很多团队同时维护订阅号和服务号,后台数据库里存的 openid 没区分来源,结果拿订阅号的 openid 去调服务号的模板消息接口,返回40003(invalid openid)。
排查这类问题,第一是看数据库字段有没有区分公众号标识,第二是在日志里记录调用时的 appid、openid、接口类型。我在项目里习惯给用户表加一个appid字段,所有 openid 都跟着 appid 走,彻底避免混用。
6.4 跳转链接被微信拦截
模板消息里带的 url 如果域名没备案、或者被微信安全检测判定为可疑链接,用户点击时会被拦截。这个问题往往在开发环境不明显,上线后才发现。
提前预防的方法:确认跳转域名已经备案,且在微信后台“业务域名”配置里加过白名单;如果跳转小程序,要确认 miniprogram 参数里的小程序 appid 已经关联到你的公众号。反过来也提醒一点:不要为了短链把 url 换成不明来源的跳转服务,被封的风险很高。
6.5 用户拒绝或拉黑后的消息下发
如果用户取消关注了你的公众号,你调用模板消息接口会返回一种错误码(常见是43004或类似表示用户未关注)。很多项目在循环发通知时报错中断,其实是因为没有做失败用户的剔除逻辑。
我的建议是:定时跑一个对账任务,把发送失败且明确提示未关注的用户从数据库里标记移除,避免每次推送都带上无效 openid,浪费时间也容易触碰频控。
6.6 被判定为滥用后的封禁风险
最严重的情况是接口被封禁。触发点通常是:营销内容混进模板消息、短时间内高频下发、或者用户投诉率过高。封禁后后台模板消息入口会显示不能使用,申诉流程也比较漫长。
所以模板消息一定要坚持“服务通知”定位,不要在模板内容里加促销语、优惠券引导、联系客服话术。规范一点的团队会建立内容审核机制,所有模板文案先过一遍自查清单再接接口,避免人为失误导致整体封禁。
7. 最终决策建议:什么业务选什么号
做模板推送的选型,不能只看“哪个号的权限更全”,要结合业务的触达目标、内容频率、用户生命周期来决策。
如果你的业务是电商、医疗、金融、教育这类强交易、强预约属性的场景,核心是让用户第一时间看到“订单状态变了”“预约时间到了”“审核结果出来了”,那就老老实实注册服务号。每年300元的认证费跟用户流失相比,完全是九牛一毛。服务号的模板消息+小程序组合,是公众号体系里最稳的业务通知闭环。
如果你的业务是媒体内容、知识分享,或者只是一个引流渠道,那订阅号更适合。每天一次的群发权限让你能持续生产内容,模板消息则作为辅助通知使用——但要注意,订阅号模板消息触达位置差,别把它当成主力通知通道。此时可以设计一个“内容号 + 服务号”的矩阵:订阅号负责拉新和日常内容,服务号负责转化和留存通知。
还有一种情况是预算有限、主体资质不全的初创团队。可以先注册订阅号,用测试号把整套开发逻辑跑通,等具备企业资质后再注册服务号迁移业务。订阅号阶段不要死磕模板消息,用客服消息+群发消息来替代,虽然体验打折扣,但能保证业务先跑起来。
最后再多说一句:微信官方对公众号消息能力的规则一直在微调,包括模板库的更新、频控策略的变化、新通知形态的出现,做这块一定不要只看两三年前的教程。落地的原则始终是——搞清楚自己的核心场景,用最合适的消息通道,保持克制,把每一次推送都做成用户真正需要的信息,而不是完成公司KPI的营销弹窗。按照这个原则去选型和开发,服务号或订阅号都能做出稳定不翻车的模板推送系统。