Configuring the ten push channels: from WeCom to your own webhook

Configuring the ten push channels: from WeCom to your own webhook

WeCom, DingTalk, Feishu, Bark, the WeCom app, SMTP, PushPlus, MagicPush, a generic webhook, MeoW — what each one needs, what to type where, where each one bites you, and a troubleshooting table.

November 8, 20262026年11月8日
14 min read约 8 分钟

阅读中文版 →

Installing the bot is step one. What decides whether it’s any good is where the message actually lands — in a WeChat group, on your lock screen, or in a webhook you wrote yourself.

It supports ten channels and each one has its own personality. DingTalk wants a keyword. The WeCom app wants your IP allowlisted. Email wants an app password, not your login password. MagicPush will 403 you if the base URL is wrong. This post is the side-by-side manual for all of it, pulled from the docs/channels/ files in the repo, merged and extended with the traps and the troubleshooting.

Push channels and system settings

Pick a channel by where you read messages

ChannelWhere it landsWhat it needsWho it’s for
WeCom (group bot)A WeChat group messageA WeCom org plus a group bot webhookDefault pick. You see it right in WeChat
WeCom appWeChat / WeCom, addressed to a personA self-built app plus trusted IPsYou want to target one person or department
DingTalkA DingTalk groupGroup bot plus a custom keywordYour team lives in DingTalk
FeishuA Feishu groupGroup bot webhookYour team lives in Feishu
BarkAn iOS notification (lock screen banner)Bark app plus your device URLThe fastest option on iOS
PushPlusA WeChat template messageA tokenYou already have a PushPlus account
SMTP emailYour inboxAn SMTP server plus an app passwordYou want an archive, forwarding, or no phone push
MagicPushWhatever you point it atMagicPush deployed, base URL, tokenYou want one place to manage many devices and channels
Generic webhookAny HTTP serviceA URL that accepts a POSTntfy, Gotify, Home Assistant, n8n, your own thing
MeoWA phone notificationA nickname registered in the MeoW appAndroid or iOS with the least possible setup

My advice is start with two: WeCom (in a group, so you can scroll back) and Bark (on the lock screen, so you see it immediately). One covers “I’ll check later”, the other covers “tell me now”. Send important things to both — there’s no conflict, channels deliver in parallel.

Three ways to configure it, and the priority order

Any channel can be set up three ways:

  1. The web config page: add channel → pick the type → paste the URL or JSON → save → hit “Send test” at the bottom of the page.
  2. config/config.json: write the fields directly, e.g. wechat_webhook_url, smtp_params, webhook_params.
  3. Environment variables: e.g. WECHAT_WEBHOOK_URL, SMTP_PARAMS, WEBHOOK_PARAMS.

Priority: environment variables > config.json / the web page. If a key came from the environment, the config reader skips it outright. So “I changed it in the UI and nothing happened” is by design, not a bug. When a config change doesn’t take, check this first.

Multiple sets of the same channel: pushplus_params, smtp_params, wecom_app_params, webhook_params and meow_params all accept several entries separated by a pipe |, for example:

{"token":"aaa"}|{"token":"bbb"}

⚠️ If the JSON itself needs a | (the WeCom app’s to_user, say), write \u007c or it’ll be split as a separator. Saving through the web page handles this for you.

WeCom group bot: bind an admin WeChat account

This is where most people get stuck, and the cause isn’t the tool — it’s WeCom’s signup flow:

  1. Go to work.weixin.qq.com and register an org (any name works, including a personal one);
  2. You have to bind an admin WeChat account, otherwise messages won’t reach you in WeChat later;
  3. In the admin console, under My Enterprise → WeChat Plugin (我的企业 → 微信插件, the labels are Chinese even in the English UI), find the option that must stay unchecked — check it and you can only receive inside the WeCom app;
  4. Log into WeCom, open the default group → ... in the top right → message push → add bot → save, and you have your webhook.

The string you get back, https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=..., is a password. Anyone holding it can post into your group. Don’t screenshot it, don’t commit it to a public repo.

One limit worth knowing up front: a WeCom group bot takes 20 messages per minute. That’s exactly why a poll that reads dozens of events goes out as one summary — send them individually and the rate limiter silently drops them.

DingTalk: the keyword has to match your title prefix

DingTalk group bots have a security setting with four options. Custom keyword is the easy one, but the keyword isn’t free-form:

it has to equal the event title prefix in the app, which lives under system settings at the bottom of the config page and defaults to 飞牛NAS. DingTalk checks whether that string appears in the message body, and the title prefix gets prepended to every message title.

The symptom when they don’t match is unmistakable: DingTalk reports no error, the log says success, and the message never appears.

Two smaller traps:

  • A DingTalk group needs at least two members. Invite someone, create the group, then remove them.
  • If you switch to the signature option (加签) instead, set the security setting to signing — you can’t use it alongside the keyword.

Feishu: you can create a group alone, just don’t add outsiders

Feishu is more relaxed than DingTalk: one person can create a group. Group settings → group bots → add bot → custom bot → copy the webhook.

Two things to watch:

  • On a personal account, don’t invite external people. It triggers cross-org restrictions and the bot may not be able to post.
  • The security setting can be left empty, or you can use a keyword like DingTalk — and it has to match the event title prefix too.

Paste the Feishu webhook into the app, set the channel to Feishu, and you’re done.

WeCom app: the most capable, blocked on trusted IPs

If you don’t want messages in a group but addressed to a specific person, department or tag, use a self-built app:

  1. The corp ID is at the bottom of the My Enterprise page (我的企业) in the admin console;
  2. App management → self-built → create app, then note the AgentId and Secret (you have to read the Secret in the WeCom client);
  3. In the app’s details, add the recipients to its visible scope, otherwise nothing gets through;
  4. Configure trusted corporate IPs with the public IP your NAS goes out on.

Step 4 is the pain point. Without it the API returns:

60020  not allow to access from your ip

And home broadband public IPs change, so what worked stops working. Two ways out:

  • Put a server with a static IP in front as a reverse proxy to https://qyapi.weixin.qq.com, then point the app’s API address at the proxy;
  • or accept it and come back to edit the IP whenever it changes.

Also, for apps created after June 2022, you usually have to set a trusted domain or a receiving URL before you can configure trusted IPs. Follow whatever the console asks for.

The config JSON looks like this:

{"corp_id": "ww1234567890abcdef", "corp_secret": "应用Secret", "agent_id": "1000002", "to_user": "@all"}

If to_user, to_party and to_tag are all empty, it goes to @all — everyone inside the app’s visible scope.

Bark: one URL and it’s on your lock screen

Bark is the least work on iOS. Install the app, the home screen shows a URL that’s yours, paste it into the app and set the channel to Bark. Done.

Want nicer notifications? Put the {content} placeholder in the URL:

https://api.day.app/你的Key/这是我的标题/{content}
https://api.day.app/你的Key/{content}?icon=https://day.app/assets/images/avatar.jpg

The first line sets a custom title, the second a custom icon. {content} gets replaced with the message body. That placeholder is yours to add — leaving it out is fine.

SMTP email: an app password, not your login password

Email is the most commonly misconfigured channel, because everyone reaches for their mailbox password. SMTP wants an app password (sometimes called an authorization code).

Setup: turn on SMTP in your mail provider’s settings, generate the app password, and note the server and port.

{
  "server": "smtp.qq.com",
  "port": 465,
  "username": "yourname@qq.com",
  "password": "邮箱SMTP授权码",
  "from": "飞牛告警",
  "to": "receiver@example.com,backup@example.com"
}
FieldRequiredNotes
serverYese.g. smtp.qq.com
portNodefaults to 465
usernameYesusually the full address
passwordYesthe app password, not the web login password
toYesseveral recipients separated by commas
fromNodisplay name; without an @ it’s treated as a nickname and shown alongside the login address

The port decides the encryption, there’s no separate switch:

  • 465 → SMTP_SSL (implicit TLS);
  • anything else (587 usually) → plain connection, then STARTTLS.

Common providers:

ProviderServerPort
QQ Mailsmtp.qq.com465 / 587
NetEase 163smtp.163.com465 / 587
Outlook / Microsoft 365smtp.office365.com587
Gmailsmtp.gmail.com587 (app password required)

When mail won’t send, check in order: is the app password the current one → does the port match what the provider wants → has the provider restricted SMTP on your account.

MagicPush: don’t put the reverse-proxy domain in there

MagicPush is a self-hosted push aggregator: you configure your downstream channels in it (Bark, WeCom, email…), and the bot sends once to MagicPush, which fans out.

Two values to keep straight:

  • Base URL: the service root, without /api/push. On the same host, use the LAN address, http://192.168.1.10:818;
  • Access token: the token on the push endpoint under Interface Management (接口管理), not the JWT you log in with.

Three errors that come up constantly:

What you seeWhy
HTTP 403The base URL is a reverse-proxy domain like https://xxx.fnos.net — the container loops out to the public domain and back in, and the proxy usually blocks it. Use LAN IP:port instead
Can’t connectYou used localhost / 127.0.0.1, which inside Docker means the container itself
HTTP 400: 部分推送失败It did reach MagicPush, and one of its downstream channels failed. Go look in MagicPush

Generic webhook: talk to anything

For platforms without a built-in channel — ntfy, Gotify, Server酱, Home Assistant, n8n, something you wrote — use the generic webhook. Any 2xx counts as success.

It sends POST + JSON by default, with a body of {"title": "标题", "content": "正文"}. If you need auth or specific fields, open the advanced options and set headers or a body template:

{
  "url": "https://example.com/hook",
  "method": "POST",
  "content_type": "json",
  "headers": "Authorization: Bearer xxx",
  "body": "{\"title\": \"{title}\", \"content\": \"{content}\"}"
}

Four placeholders:

PlaceholderContents
{title}The message title
{content}The message body
{text}Title plus body as one plain-text string
{time}Send time, YYYY-MM-DD HH:MM:SS

Placeholders get escaped according to the content type — quotes and newlines escaped in JSON, URL-encoded in forms and URLs, substituted as-is in plain text. Which means the template itself has to be valid JSON, or the request never leaves.

Three ready-made examples:

  • ntfy: URL https://ntfy.sh/你的主题, method POST, plain text, body {text};
  • Gotify: URL https://gotify.example.com/message?token=xxx, JSON body {"title": "{title}", "message": "{content}"};
  • GET push: URL https://example.com/push?msg={text}, method GET (no body).

One thing was done for safety: the runtime log doesn’t print query parameters, and when the config page echoes back a URL, tokens and keys in the address plus auth headers like Authorization, Token and Cookie come back masked — and the masked values are restored on save if you didn’t touch them. So screenshotting the config page is safe.

MeoW: a nickname is enough, but get it right

MeoW is a phone push app, and it needs exactly one thing: a nickname.

{"nickname": "你的昵称", "url": "http://192.168.1.10:5666"}

url is optional; set it and tapping the notification opens it, say your NAS home page.

Three hard limits you need to know about:

  • Free tier rate limits: 1 per 3 seconds, 15 per minute, 60 per hour, 1000 per day. Over that you get 429;
  • Pushing to an unregistered nickname gets your IP banned cumulatively: three pushes to unknown nicknames in one day from the same IP and you’re blocked. So when the bot sees “nickname not registered” it stops pushing to that nickname automatically, and resumes once you fix the nickname and save;
  • Don’t push from a shared public egress IP — that’s how you get flagged as an attack.

When events are busy, turn on poll-batch summary mode, or you’ll hit the rate limit fast.

Don’t let your own tool annoy you

Once the channels work, the thing to tune isn’t the channel — it’s the pace. Four switches:

SwitchWhat it doesHow I set it
Event selectionOnly push what you care aboutTurn on login failures / disk problems / container crashes / UPS first, leave the rest off
Poll-batch summaryMany events in a short window become oneOn when events are busy, or when the channel has rate limits (MeoW, email)
Minimal pushEverything squeezed into one lineOn while you only care “is something wrong”, off when you want detail
Do not disturbNothing during the window, one digest afterDefaults to 22:00–07:00, cross-midnight handled for you

And one backstop underneath: a 300-second dedupe window — the same event goes out once per 5 minutes. A disk waking up repeatedly, SSH brute-force attempts, all of that gets absorbed by this and by the 5-second merge window. Otherwise your phone really does get buzzed flat.

Troubleshooting table

When something doesn’t work, read this before you read the logs:

SymptomLikely causeFix
WeCom never notifiesAdmin WeChat not bound, or the “receive in WeCom app only” option got checkedGo back to the WeCom group bot section and redo it
DingTalk logs success, no messageCustom keyword ≠ event title prefixSet it to match title_prefix (default 飞牛NAS)
Feishu can’t sendExternal members in the groupUse an internal-only group
60020WeCom app has no trusted IPAdd the public IP, or proxy through a static IP
40001 / 40013Wrong corpid or SecretCheck that the Secret belongs to that AgentId
81013Recipient outside the app’s visible scopeAdd them to the visible scope
Mail 535 / auth failedLogin password instead of app passwordGenerate a new app password
Mail times outPort and encryption mode don’t match465 or 587, per the provider’s docs
MagicPush 403Base URL is a *.fnos.net reverse proxyUse LAN IP:port
MagicPush 400 部分推送失败A downstream channel failedCheck MagicPush’s own logs
MeoW 429Rate limitedTurn on poll-batch summary, or upgrade
MeoW 404Nickname not registered or misspelledFix the nickname and save
Webhook does nothingTemplate isn’t valid JSONValidate the JSON locally first
Every channel silentEnvironment variables overriding the configLook for *_PARAMS and friends

One last thing

Ten channels sounds like a lot. In practice you’ll use two or three. Get one working, click “Send test” until it’s green, then add the next — that’s much faster than configuring five and having no idea which step broke.

The “Send test” button at the bottom of the config page exists for exactly this: it reports each channel separately — which one succeeded, which one failed, and what came back.

Related reading: