Skip to content

Commit 9542945

Browse files
committed
New blog post #23
1 parent 7a08022 commit 9542945

2 files changed

Lines changed: 174 additions & 0 deletions

File tree

posts/entries/023-wechat-bot.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
title: Scheduling a WeChat message (Or, why I ended up hitting send)
3+
date: 2025-11-25
4+
tags: [life, cs]
5+
author: R
6+
location: Manhattan, NYC
7+
---
8+
9+
This all started with a very ordinary situation.
10+
11+
I was going through my WeChat chats tonight and realized I'd never replied to someone I met at a networking event. I told myself I'd follow up "later." Later became "oops, it's already late (at night) and I still haven't replied."
12+
13+
Now, I had a different problem:
14+
15+
- If I reply **right now**, it's kind of a weird timing - like sending email to someone after work hours.
16+
- If I wait until **tomorrow morning**, that feels like a nicer follow-up window: awake, thoughtful, polite, etc. Same reason someone would schedule an email to go out at 9am.
17+
18+
So an obvious question pops into my head:
19+
20+
> Could I just schedule a message for tomorrow morning???
21+
22+
You can probably guess how this ends.
23+
24+
---
25+
26+
## The initial idea: treat WeChat like email
27+
28+
Email clients have had "Send later" since forever. You write the thing, pick a time, and forget about it. The client on the server does the boring waiting part.
29+
30+
I wanted exactly that but for WeChat:
31+
32+
1. Draft the message at night.
33+
2. Choose a time like 9:15am tomorrow.
34+
3. Forget about it.
35+
36+
Except WeChat doesn't do that. There's no such button, no built-in delay feature. (WeCom does have that API but it's more of a workspace app.) If I want the effect of a scheduled message, there are two realistic options:
37+
38+
- Remember to open the chat myself and hit send at 9:15am, or
39+
- Use some external thing as a reminder (Reminders app, calendar, etc.)
40+
41+
At this point, a normal person would just move on. Apparently I'm not so normal, too autistic I guess.
42+
43+
---
44+
45+
## "Why can't I just write a program?"
46+
47+
My brain starts to produce these incredibly annoying thoughts like:
48+
49+
> Surely I can write a (couple) script(s) to do all this.
50+
51+
The idea I had in mind:
52+
53+
- Use my Mac, with the WeChat desktop client open.
54+
- Use Python plus something like `pyautogui` to:
55+
- Select the right chat,
56+
- Paste the message into input box,
57+
- Hit Enter at exactly the time I want.
58+
- Use **cron** so the script runs at the right moment without me sitting there.
59+
60+
On paper, this is totally doable:
61+
62+
1. Cron wakes up at 9:15am and runs `python3 send_wechat.py ...`.
63+
2. The script:
64+
- `open -a WeChat`
65+
- Presses the right button to search.
66+
- Type name, press Enter.
67+
- Paste message.
68+
- Presses Enter.
69+
3. Script ends, cron goes back to sleep, life goes on.
70+
71+
Unfortunately, reality is never that simple.
72+
73+
---
74+
75+
## Sleep, brittleness
76+
77+
The first obvious problem is sleep. If I close my MacBook, the machine sleeps -> `cron` doesn't run -> nothing happens. So for this to work, I'd have to:
78+
79+
1. Keep the Mac awake and logged in at the scheduled time.
80+
2. Either leave the lid open, or use some setup with power + external display.
81+
3. Possibly run `caffeinate` so macOS doesn't decide to nap anyway.
82+
83+
Then there's the brittleness. If some random notification pops-up, the script happily types my heartfelt networking follow-up into the wrong window. Pixel-based click logic goes off with UI change.
84+
85+
---
86+
87+
## WeChat bots
88+
89+
I searched GitHub and, unsurprisingly, there are already **a bunch of WeChat bots** people have written over the years, in multiple languages. Some highlights:
90+
91+
- Bots that use desktop automation (similar in spirit to my idea).
92+
- Frameworks using reverse-engineered protocols:
93+
- Fake a Web / iPad / Mac client.
94+
- Do QR-code login
95+
- Maintain sessions
96+
- Send and receive messages, handle reconnections, etc.
97+
98+
---
99+
100+
## The architecture pattern: a typical WeChat bot
101+
102+
Same big pieces appear over and over. Roughly:
103+
104+
### 1. Transport / protocol
105+
106+
This "talks" to WeChat; manages the connection to WeChat's servers (HTTP, WebSocket, or some custom thing); Handles heartbeats, reconnects when needed; Knows how to send/parse the raw frames/XML/JSON used internally.
107+
108+
For personal-account bots, this is all unofficial and reverse-engineered.It's like "we stared at traffic long enough to figure out the pattern."
109+
110+
### 2. Login & session management
111+
112+
Most personal WeChat bots use QR code to login, The process goes like:
113+
114+
1. The bot asks WeChat for a QR code.
115+
2. Scan it with phone
116+
3. WeChat allowed this weird client to act as you
117+
4. The bot gets session tokens/cookies.
118+
5. The bot saves these tokens somewhere (file, DB) for reconnecting until expiration.
119+
120+
Official-accounts / enterprise stuff looks different (app IDs, secrets, access tokens), but the idea of some token layer is the same.
121+
122+
### 3. Data models: `Message`, `Contact`, `Room`
123+
124+
`Message` is with, `from`, `to`, (and optional `room`), type (text, image, etc.), convenience methods like `.text` and `.say(...)`. There's also `Contact` / `ContactSelf` for people (including the bot), `Room` for group chats, with methods to send messages to the whole group.
125+
126+
These code never needs to deal with low-level protocol junk directly; it just works with these objects.
127+
128+
### 4. Event Core
129+
130+
At the center is an event loop that listens for new messages(events) from the transport. For each one, it constructs a `Message` / `Room` / `Contact` object. It emits events like `on_message(message)`, `on_room_join(...)`, `on_friendship(...)`, `on_login(...)`.
131+
132+
### 5. Handlers
133+
134+
On top of all that it comes actual "behaviors" which I'm too lazy to list out fully. In the "nice" repos these show up as plugins:
135+
136+
```text
137+
handlers/
138+
echo.py
139+
auto_reply.py
140+
welcome_new_member.py
141+
send_daily_summary.py
142+
```
143+
144+
If I did wrote a scheduled follow-up bot, this is probably where the logic would go.
145+
146+
### 6. Important stuff
147+
148+
Usually, config files (for tokens, IDs, etc.), database or key-value store to remember state, some kind of scheduler...(internal ones like APScheduler, external (cron + HTTP callbacks), sth. part of a bigger task system (Celery, etc.))
149+
150+
That original "schedule one message" look tiny compared to this large pile.
151+
152+
---
153+
154+
## So what was the point of all this?
155+
156+
All of that just so I can avoid sending a message at 10pm and instead have it go out at 9:15am. At some point, after thinking through all that, I had the correct realization:
157+
158+
> If I'm willing to invest this much effort, I could have just... sent the message.
159+
160+
So I replied right away. It felt slightly suboptimal, but infinitely better than actually starting this mini-bot project. For things like this, a reminder app + manual send is good enough. As an afterthought, a public API for "`send_message`" would be a spammer's dream, ngl. Social media messaging apps are designed this way for a reason.
161+
162+
If I name one biggest takeaway, it's not the technical stuff:
163+
164+
> **Overengineering is a very specific kind of temptation**
165+
>
166+
> Once you know you *could* automate something, it's weirdly hard to accept you should move on. But sometimes that's just better.

posts/metadata/entries.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,13 @@
123123
"location": "Bobst 8F, New York, NY",
124124
"tags": ["math", "life", "notes"],
125125
"slug": "022-Suranyi"
126+
},
127+
{
128+
"title": "Scheduling a WeChat message (Or, why I ended up hitting send)",
129+
"date": "2025-11-25",
130+
"author": "R",
131+
"location": "Manhattan, NYC",
132+
"tags": ["life", "cs"],
133+
"slug": "023-wechat-bot"
126134
}
127135
]

0 commit comments

Comments
 (0)