每天早上醒来,都会看到手机锁频界面如瀑布般展开的News推送卡片😶‍🌫️,bilibili的,微信公众号的,还有一堆订阅的邮件。。。消息一多,读完已是晌午(有时候读着读着,就被BILIBILI推送的视频封面吸引,推送算法害人呃)。于是想效仿纸媒时代每天送到家门口邮箱中的报纸一样,做一个自动获取、排版、总结和推送指定源的自动化程序,每天生成一份个性化、简洁的电子日报。早上只需要翻阅这份“电子都市报”,妈妈再也不用担心看新闻分心了~

其实市面上已经有相关功能软件,如基于RSS源订阅的FOLO阅读器和各种类openclaw Agent。但前者订阅源有限,且没法灵活使用LLM进行信息总结和分类(页面也没办法自定义),后者获取新闻源的方法较为“笨拙”,并且我也用不到openclaw其他功能其实是花不起token,还是得自己手搓咯。如你所见,Knicknack POST项目主要分为4个功能模块:News源订阅、LLM总结、邮件排版+渲染和邮件推送

News源订阅

一开始考虑过使用网络爬虫实现。但受限于不同News源页面结构不同、需要账号登陆、源页面更新频繁等等原因,爬虫很难稳定长期运行,与POST项目初衷:长期运行,稳定性和可维护性较高相悖,遂放弃该方法。经过调研后,采取两种方法获取News:RSSHubkill_the_newsletter

RSSHub

RSS(Really Simple Syndication) 是一种用于内容订阅与分发的标准格式(基于 XML),方便自动化程序获取网站更新。就像info中提到一样,靠手动刷博客/网站获取News的方法很低效,而通过获取网站提供的“结构化更新接口”——RSS,有更新就自动推送,后者不仅更高效,还绕过了平台的推荐算法。
但许多网站并未提供RSS订阅源,RSSHub(AGPL-3.0)项目诞生了。她是一个由超过1300名贡献者维护的“万物转RSS的网关”,将整个互联网强行改造为可订阅RSS的中间层。推荐拉取docker仓库后自建服务,以免RSSHub公共实例压力太大。

1
2
3
4
5
6
7
# RSS样例
<item>
<title>...</title>
<link>https://example.com/</link>
<pubDate>Tue, 07 Apr 2026</pubDate>
<description>.....</description>
</item>

kill the newsletter

还有一些订阅平台仅提供邮件订阅服务(TLDR和changelog),可以使用自动化脚本从邮箱中获取News邮件,但推荐kill the news letter服务。该服务会将邮件订阅(Newsletter)转成RSS Feed,便于统一News源格式。不过kill-the-newsletter免费服务每一个邮箱仅保留最新的20封邮件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# kill-the-newsletter rss feed格式
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>..</id>
<link
rel="self"
href="https://kill-the-newsletter.com/feeds/....xml"
/>
<link
rel="hub"
href="https://kill-the-newsletter.com/feeds/.../websub"
/>
<icon
>https://cmail19.com/favicon.ico</icon
>
<updated
>2026-04-06T02:59:37.525Z</updated
>
<title>changelog_daily</title>

<entry>
<id>urn:kill-the-newsletter:...</id>
<link
rel="alternate"
type="text/html"
href="https://kill-the-newsletter.com/feeds/.../entries/....html"
/>

<published>2026-04-06T02:59:37.525Z</published>
<updated>2026-04-06T02:59:37.525Z</updated>
<author>
<name></name>
<email
></email
>
</author>
<title>...</title>
<content type="html">
</content>
</entry>

LLM总结

由于部分源每日推送News过多(TLDR,changelog等),可以先让LLM“洗”一次,然后推送分类并精炼后的总结文段,如果有感兴趣的部分再跳转精读。为了节省token,Knicknack-post会使用beautifulsoup库除去RSS中无关标签,仅提取description部分。目前主流LLM都能胜任该工作,本项目使用deepseek官方API平台提供的chat模型,且采用openai API格式。如需更换模型,需要修改post/目录下对应源调用LLM处和prompt-json提示词文件。

1
2
3
4
5
6
7
8
9
10
11
12
# example
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[
self.system_prompt,
{"role": "user", "content": raw_tldr_text}
],
# 开启 JSON Mode (DeepSeek 支持此参数,确保返回的是合法 JSON)
response_format={'type': 'json_object'},
temperature=0.3, # 降低随机性
stream=False
)

邮件排版+渲染

为了能自己设计日报版面,同时兼容不同邮件服务平台,选择使用HTML格式的邮件正文。Knicknack POST采用MJML生成邮件模板并转为HTML格式,然后使用Jinja2库将格式化的News填入HTML模板。

MJML

MJML(Mailjet Markup Language) 是一种专门用于构建邮件(Email)HTML的标记语言。不同于普通网页开发,邮件前端通常面临许多问题(Outlook用Word引擎渲染、Gmail会删样式等等)。为了保证不同平台显示效果一致,可以先用MJML标记语言的“高级组件语法”开发:

1
<mj-button>Click me</mj-button>

经过编译后输出兼容性极强的HTML标记文本:

1
2
3
4
5
6
7
<table>
<tr>
<td style="...inline样式(避免独立样式被删除)...">
<a href="...">Click me</a>
</td>
</tr>
</table>

Jinja2

Jinja2是一个Python的模板引擎,主要用来将“数据+模板”渲染成最终文本,其模板通常为但不限于HTML文件,相当于一个“带逻辑的字符串生成器”。

1
2
3
4
5
6
7
8
9
10
from jinja2 import Template

template = Template("""
<h1>Hello {{ name }}</h1>
""")
result = template.render(name="Alice")
print(result)

# 输出为:
# <h1>Hello Alice</h1>

邮件推送

在选择Knicknack POST项目推送形式的时候,考虑了许多种方法:

  • 使用通讯平台官方机器人。飞书个人机器人每天消息限量100条,微信和QQ功能太少,且对发送文件大小有限制。并且平台对机器人消息内容审核较严,总有一种被监视偷窥的感觉;
  • 自建即时通讯软件机器人。telegram等境外软件国内使用不太方便,QQ和微信的机器人框架需要和官方斗智斗勇,不仅一个不留神号容易进小黑屋,而且官方更新后有的框架就失效了,与项目稳定性高、可长期运行目标相悖;
  • 使用邮件服务。虽然没有即时聊天软件方便,但技术限制和内容限制更少,且看起来更高级和正式
    综合考虑后,选择使用邮件推送的方法,下面多种都可使用:

resend服务

Resend是面向开发者的邮件发送 API + 投递基础设施。其可以省去自建SMTP服务的过程。不过其本质上是一个网站邮件服务插件,需要提供自己的网站域名、和DNS记录配置,否则只能发给自己账号绑定的邮箱。

SMTPLIB/REDMAIL

SmtpLib库是python提供的smtp协议库,可以实现一些轻量化的邮件发送服务。为了避免因没有DNS IP 信誉导致发送邮件进垃圾箱,需要通过邮件平台SMTP服务器发送(本项目使用的是QQ SMTP服务器),可以在官方开放平台申请一个SMTP 授权码使用该功能。
Redmail库则是对前者的现代化封装,免去了手动构建MIME对象结构步骤,且集成了jinja2的渲染功能。


受限于店主对token价格的敏感性目前Knicknack POST是一个简单的自动化工具,仅在总结News时使用了LLM。之后该项目会逐渐变为本地类openclaw个人agent的一个功能,店主会将以上源获取、News排版和发送模块封装为 agent tools以供调用