先说说我做这个项目之前的处境。作为一个常年泡在科技圈的人,我每天至少有三分之一的时间不是在刷资讯就是在挑资讯的路上。techcrunch、the verge、hacker news、少数派、爱范儿,再加上各种公众号和即刻动态,信息源越加越多,真正读进去的反而越来越少。很多时候明明知道某条新闻很重要,但就是被淹没在信息流里看不见了。后来我干脆给自己定了一个规矩:每天只留早上半小时集中看科技新闻,其余时间一律不刷。想法很好,执行力跟不上。早上打开手机,随手点开几个app,半小时过去可能才看了两三条,剩下的时间全浪费在切换平台和跳过重复内容上。于是我决定做一个能自动抓取、自动摘要、自动推送的科技新闻邮件机器人,每天固定时间把最值得看的内容送到邮箱里,打开就能读,读完就关,干脆利落。
这个项目做下来,核心价值其实特别简单:用代码替换掉“手动刷信息流”这个低效动作,把每天被动接收的科技资讯,变成一份结构化、轻量、可归档的摘要邮件。它适合所有科技从业者、产品经理、投资人和单纯对科技动态感兴趣的人。你不需要懂太多编程也能跟着搭起来,整个项目用到的技术栈很常规——python、rss解析、文本摘要算法、smtp邮件发送、服务器定时任务,每一个环节都有成熟的库和方案可以用。这篇文章我就把完整的设计思路、实现过程、踩过的坑和最后优化出的配置全部写出来,你可以直接照着搭一套自己的。
1. 项目整体设计与思路拆解
1.1 为什么选“邮件”而不是app推送或im机器人
我先把这个问题想清楚,因为它决定了整个项目的形态。市面上已经有大量资讯类app和即时通讯机器人,reeder、inoreader、feedly,以及各种telegram bot、slack集成,都已经很成熟了。那我为什么还要自建一个邮件机器人?
核心原因有三个。第一,邮件是“非侵入式”的。它不会像app推送那样随时弹出来打断你,也不会像im消息一样被置顶、被红点提醒逼迫你立刻处理。邮件天然带有“异步阅读”的属性,你可以在固定时间打开邮箱统一处理,这正好匹配科技新闻的浏览节奏。第二,邮件有天然的归档和搜索能力。一封摘要邮件发过来,过了一个月你还能通过关键词把当天的科技动态搜出来,这比im聊天记录里翻找要可靠得多。第三,也是最重要的一点——邮件协议足够通用和稳定。无论用什么手机、什么系统,邮箱都是标配,不需要额外装任何软件,也不依赖某些im平台的接口限制。
当然我也承认,即时通讯机器人有它的优势,比如交互更灵活、可以点击按钮展开详情。但如果你追求的是“简洁、自动、不打扰”,邮件是目前最合适的载体。而且实现起来,smtp协议几乎是所有编程语言的标准能力,部署成本低到可以忽略。
1.2 整体架构与数据流转
整个系统的数据流其实很清晰,我拆成了五个阶段:
- 数据源获取:定时从多个科技新闻源抓取rss订阅内容,拿到最新的文章列表。
- 内容解析清洗:把每篇文章的标题、链接、发布时间、正文摘要提取出来,去掉html标签和无用信息。
- 摘要生成:对正文内容做文本处理,提取出3到5个核心要点,形成简短的摘要文本。
- 邮件聚合:把当天所有来源的新闻摘要整合成一个html邮件,按来源分组、按时间排序,加上统一的样式模板。
- 定时发送调度:通过cron定时任务在每天固定时间唤醒脚本,完成上述全流程并调用smtp服务发送邮件。
这个流程的单向性很强,所以我一开始就按“管线”的思路来写代码,每个阶段封装成独立函数,输入输出都是标准数据结构。好处很明显:任何一个环节出了问题,可以单独测试、单独修复,不会连累其他模块。比如新闻源解析挂了,摘要生成和邮件发送仍然能正常工作,只是邮件里会少一个来源的内容。
1.3 技术选型:python生态的取舍
技术栈方面,我选的是python,主要因为它的第三方库生态对这类任务支持太好了。rss解析用feedparser,一发入魂,不需要自己写xml解析逻辑;http请求用requests,处理超时和重试很方便;html内容清洗用beautifulsoup;文本摘要处理用sumy库的textrank算法,或者自己实现一个轻量级的句子打分方案;邮件发送直接用标准库smtplib和email.mime,不需要额外装包。
有人可能会问,为什么不直接用现成的自动化服务,比如ifttt、zapier,或者直接用feedly的邮件推送功能?我也试过。ifttt和zapier的免费额度限制比较多,规则配置也偏简单,很难做到自定义的摘要抽取和html排版。feedly的邮件推送只能按rss源原样推文章,没有摘要精炼的过程,邮件正文往往很长。最关键的是,这些第三方服务的处理对用户来说是个黑盒,你没法细化摘要逻辑,也没法在发送前做任何自定义的数据处理。自己写代码的好处就是每个环节都可控、可调试、可迭代。
当然,有得必有失。自建方案需要你自己维护一台能定时运行脚本的设备,比如家里开着的电脑、树莓派,或者一台便宜的云服务器。这一点在后面的部署章节我会展开讲。
2. 核心模块与关键技术实现
2.1 数据源获取:rss解析与请求策略
先看数据源这一层。科技新闻类的rss源非常多,我这边最终选了6个固定源,兼顾了国际和中文内容,覆盖综合科技、深度长文和开发者社区三个维度。每个源的质量都不一样,有的rss提供全文正文,有的只给摘要,有的一篇只有一句话加链接,所以在选源的时候最好自己先逐个测试一遍。
我用的是feedparser这个库,代码非常简单:
import feedparser
def fetch_feed(feed_url):
"""抓取单个rss源的最新文章列表"""
try:
feed = feedparser.parse(feed_url)
entries = []
for entry in feed.entries[:15]:
entries.append({
"title": entry.get("title", "").strip(),
"link": entry.get("link", "").strip(),
"published": entry.get("published", ""),
"summary": entry.get("summary", "")[:500],
"source": feed.feed.get("title", feed_url),
})
return entries
except exception as e:
log_error(f"抓取失败: {feed_url}, 错误: {e}")
return []
这段代码有几个细节值得说一下。第一,我只取每个源最新的15条,因为每天真正值得看的科技新闻量级有限,取太多反而增加后续摘要处理的噪音。第二, summary 字段我截断了500个字符,这是为了控制数据集大小,避免某些rss源一次性塞入几千字的正文导致后续处理变慢。第三, feed.feed.get("title", feed_url) 用于提取站点名称,后续邮件分组的时候会用到。
请求策略上我做了两个处理。一个是设置合理的user-agent请求头,标明自己是哪个项目在抓取,这既是礼节问题,也是降低被服务器拒绝的风险。另一个是加超时控制,requests库默认没有超时,如果不手动设置,某个源挂掉会导致整个脚本卡在那里。我在请求层加了8秒超时和最多两次重试,具体代码如下:
import requests
def fetch_feed_with_retry(feed_url, timeout=8, retries=2):
headers = {
"user-agent": "technewsdigest/1.0 (personal rss aggregator)"
}
for attempt in range(retries):
try:
resp = requests.get(feed_url, headers=headers, timeout=timeout)
resp.raise_for_status()
return feedparser.parse(resp.content)
except requests.requestexception as e:
if attempt == retries - 1:
log_error(f"请求失败: {feed_url}, 错误: {e}")
return none
time.sleep(2)
2.2 摘要生成:从“截取开头”到“提取要点”
摘要模块是整个项目里最有技术含量的部分。如果你只是想把新闻标题和正文开头塞进邮件,那其实不用做摘要——但那样邮件会显得很臃肿,没有“摘要邮件”应有的精炼感。
我最初用的是最朴素的方法:直接截取每条新闻正文的前300个字符。试了两天就发现问题了。很多科技媒体的导语部分写得比较委婉,开头两句往往是“某某公司于今日宣布了其最新的产品计划”,真正有价值的信息——产品名、核心指标、发布时间——可能要到第三四句才出现。直接截开头会导致摘要里全是废话。
于是我换成了基于句子重要度评分的方案。思路不复杂:先把正文按句号、问号、感叹号拆分成句子列表,然后对每个句子打分,分数综合考虑几个因素——句子在文中的位置(越靠前权重越高)、句子中包含的关键词数量(科技类高频词,比如“发布”“推出”“芯片”“融资”“收购”“更新”等)、句子长度(过短的可信息量低,过长的可能是堆砌废话)。最后按得分排序,取前3至5句拼成摘要。
如果不想自己写这套打分逻辑,也可以用现成的sumy库,它实现了textrank算法,原理上类似于把文章句子构建成一张图,通过句子之间的相似度传播来找到最核心的句子。实际效果不错,但有一个问题——textrank对中文文本的分词依赖比较重,如果不安装jieba分词,中文句子的相似度计算效果会打折扣。我的项目源里中文和英文内容都有,所以最终没有直接用sumy,而是用了自己写的中性方案,对中英文都友好。
一个关键细节是:对每条新闻做摘要的时候,不要让摘要函数抛异常导致整个任务中断。我用了try-except包裹,万一某篇正文剖析失败,就退回到截取开头的方式。这样做的好处是鲁棒性更强,不会因为单条数据质量问题打断了全流程。核心代码如下:
import re
def generate_summary(text, max_sentences=3):
"""基于句子重要度评分的简易摘要生成器"""
if not text or len(text.strip()) < 50:
return text.strip()[:300]
# 拆分句子
raw_sentences = re.split(r"[。!?!?\.]", text)
sentences = [s.strip() for s in raw_sentences if len(s.strip()) > 15]
if len(sentences) <= max_sentences:
return " ".join(sentences)[:500]
# 科技领域关键词,用于句子加权
keywords = ["发布", "推出", "芯片", "融资", "收购", "更新", "升级",
"launch", "release", "chip", "funding", "acquisition", "update"]
scored_sentences = []
for idx, sentence in enumerate(sentences):
score = 0.0
# 位置权重:越靠前分数越高
score += max(0, 1.0 - idx * 0.05)
# 关键词权重
keyword_hits = sum(1 for kw in keywords if kw.lower() in sentence.lower())
score += keyword_hits * 0.5
# 长度惩罚:太长或太短都降低分
if len(sentence) > 200:
score -= 0.3
scored_sentences.append((score, sentence))
scored_sentences.sort(key=lambda x: x[0], reverse=true)
selected = [s for _, s in scored_sentences[:max_sentences]]
# 按原句顺序重新排列,保证逻辑通顺
ordered = [s for s in sentences if s in selected]
return "".join(ordered)[:500]
这段代码不算复杂,但实用性很高。句子位置权重模拟了“导语优先”的新闻写作规律,关键词加权则让摘要更偏向于包含实际信息量的句子。几个月的运行下来,这种摘要方案的输出质量比单纯截取开头好很多,读者往往能一眼判断出这条新闻值不值得点开看全文。
2.3 html邮件模板与内容聚合
邮件正文我采用的是html格式,因为纯文本的排版能力太弱了,几十条新闻堆在一起很难扫读。html模板的设计原则是“移动端优先”——考虑到大多数人会在手机上打开邮件,我尽量不用多列布局,而是用简单的单列结构。每封邮件分成几个部分:顶部是一句问候和日期,中间按来源分组列出新闻条目,每个条目包含标题、摘要、来源名称和原文链接。
模板里我用的是内联css,因为大多数邮件客户端(尤其是gmail和outlook)会过滤掉 <style> 标签里的样式,只保留元素上的style属性。这是一个非常容易踩的坑,我第一次发出来的邮件就是“裸奔”状态,排版全部丢失,排查了半天才发现是邮件客户端的安全策略把全局样式表干掉了。
邮件组装的核心代码如下:
from email.mime.text import mimetext
from email.mime.multipart import mimemultipart
def build_html_email(articles_by_source, date_str):
"""根据分组后的文章数据生成html邮件正文"""
html_parts = []
html_parts.append(f"<html><body style='font-family: -apple-system, arial, sans-serif; max-width: 680px; margin: 0 auto; padding: 20px;'>")
html_parts.append(f"<h2 style='color: #333; border-bottom: 2px solid #eee; padding-bottom: 12px;'>科技新闻摘要 · {date_str}</h2>")
for source_name, articles in articles_by_source.items():
html_parts.append(f"<h3 style='color: #2c3e50; margin-top: 28px;'>{source_name}</h3>")
for article in articles:
title = article["title"]
summary = article.get("summary", "")
link = article["link"]
html_parts.append(f"<div style='margin-bottom: 20px; padding: 12px; background: #f9f9f9; border-radius: 6px;'>")
html_parts.append(f"<a href='{link}' style='color: #1a4f8b; font-size: 16px; font-weight: 600; text-decoration: none;'>{title}</a>")
html_parts.append(f"<p style='color: #666; font-size: 14px; line-height: 1.6; margin-top: 6px;'>{summary}</p>")
html_parts.append(f"<span style='color: #999; font-size: 12px;'>{source_name}</span>")
html_parts.append(f"</div>")
html_parts.append("</body></html>")
return "".join(html_parts)
有一点需要提醒:所有文章标题和摘要插入html之前,必须做html转义处理,否则文章标题里如果出现了 < 或 & 之类的字符,轻则样式错乱,重则破坏整个邮件结构。我用了 html.escape 函数来处理标题和摘要字段后再插入到模板里。
2.4 邮件发送:smtp封装与常见坑
邮件发送用python标准库就够了。smtplib负责网络传输,email.mime负责构造符合mime标准的邮件对象。我配置的smtp参数全部放在config.py里,方便切换不同的邮箱服务商。下面是发送邮件的核心代码:
import smtplib
from email.mime.text import mimetext
from email.mime.multipart import mimemultipart
from email.header import header
def send_email(subject, html_content, config):
"""通过smtp发送html邮件"""
msg = mimemultipart("alternative")
msg["subject"] = header(subject, "utf-8")
msg["from"] = config["smtp_user"]
msg["to"] = config["to_email"]
part = mimetext(html_content, "html", "utf-8")
msg.attach(part)
try:
server = smtplib.smtp_ssl(config["smtp_server"], config["smtp_port"], timeout=15)
server.login(config["smtp_user"], config["smtp_password"])
server.sendmail(config["smtp_user"], [config["to_email"]], msg.as_string())
server.quit()
log_info("邮件发送成功")
return true
except smtplib.smtpexception as e:
log_error(f"邮件发送失败: {e}")
return false
这里有一个重要的编码处理:邮件主题使用 header(subject, "utf-8") 来编码,否则包含中文的标题在某些邮件客户端里会出现乱码。发送方式我特意用了 smtp_ssl 而不是 smtp ,因为主流邮箱服务商的465端口普遍支持ssl加密,安全性更好,也免去了手工启动starttls的麻烦。
关于smtp密码,需要注意的一个大坑是:绝大多数邮箱服务商不直接使用邮箱登录密码作为smtp授权码,而是需要在邮箱设置里单独开启smtp服务并生成一个授权码。比如qq邮箱在“设置—账户—pop3/imap/smtp服务”里开启服务,然后会生成一串授权码,这个授权码才是smtplib登录时要用的密码。这点好多新手第一次做的时候都会困惑很久。
3. 定时调度与自动化部署
3.1 cron定时任务配置详解
代码写完之后,自动化才是让它变成“每日机器人”的关键。我选择的是linux系统的cron定时任务,因为它简单、可靠,不依赖任何守护进程或第三方调度工具。macos用户也可以用crontab,参数基本完全一致。
先看一个基础配置示例。假设我把项目放在 /home/technews/digest_bot/ 目录下,主入口脚本是 main.py ,那么crontab里的配置行长这样:
30 7 * * * cd /home/technews/digest_bot && /usr/bin/python3 main.py >> logs/cron.log 2>&1
这行的意思是:每天上午7点30分,先进入项目目录,然后用python3执行main.py,并把标准输出和错误输出都追加到日志文件里。 30 7 * * * 是crontab的五段式时间表达式,分别代表分钟、小时、日、月、星期。 * * * * * 表示所有值都匹配,所以 30 7 * * * 就是每天7点30分执行一次。
在实际运行中,有几个cron相关的问题非常容易踩。第一个是环境变量问题。cron执行任务时的环境变量跟你在终端里手动执行脚本时不一样,最典型的是 path 变量——终端里可能有 /usr/local/bin ,但cron的默认path很窄,可能找不到你安装的python。所以我的cron配置里显式指定了python的绝对路径,而不是直接写 python3 。第二个是当前工作目录问题。如果你的脚本里有相对路径读取配置文件的操作,在cron里执行时很可能因为工作目录不对而报错,所以我用了 cd /home/technews/digest_bot && 来确保脚本在正确的目录下运行。第三个是输出重定向问题。 >> logs/cron.log 2>&1 这串不是可选项,如果不把输出重定向到文件,cron执行异常时你根本看不到任何报错信息。
3.2 时区与发送时间的选择
定时任务的时间选择也值得琢磨。设计邮件的用户画像就是“每天早上一次性获取科技动态”,所以发送时间应该在目标读者开始阅读之前。我自己用的是服务器默认的utc时间,但服务器可能部署在海外,时区跟国内不同,于是我在脚本里显式设置了时区:
import os os.environ["tz"] = "asia/shanghai" time.tzset()
这样即使服务器的系统时区是utc,脚本内部处理日期和日志时间时也会统一用北京时间,避免了“计划7点发送结果下午3点才发出去”的迷惑情况。发送时间我最终定在早上7点,因为对大部分上班族来说,7点之后到9点之间是一个阅读缓冲期,邮件在7点前到达收件箱,既不会太早打扰休息,也能在出门前完成阅读。
3.3 部署方案与进程守护
我自己最初是跑在一台树莓派上的,后来因为家里网络不稳定,干脆迁到了一台1核1g的低配云主机上,一年成本很低。主要原因是脚本每天只需要在固定时间跑几分钟,对机器性能要求极低。
如果你希望更精细地控制脚本的运行状态,比如实现“运行异常自动重启”,可以引入systemd的timer替代cron。systemd的好处是可以声明服务依赖、设置失败后的自动重启策略。但对于这个项目来说,我认为cron已经足够了——它是一个有明确终点的批处理任务,执行完就退出,不存在长期驻留的问题,所以也不需要supervisor那种进程守护工具。把cron和日志配置好,剩下的就是偶尔看一眼日志文件确认是否正常。
4. 常见问题与排查技巧实录
4.1 常见问题速查表
这个项目运行了快半年,我把遇到的典型问题和排查思路整理成了表格,方便大家对照处理。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 邮件一直收不到 | smtp配置错误或服务商限流 | 先检查日志中的发送结果;再用命令行工具 swaks 或python脚本单独测试smtp连接;确认授权码是否正确 |
| 邮件进了垃圾箱 | 发信域名/邮箱信誉度低 | 在邮箱里把发件人添加为联系人;尽量用主流的邮箱服务商作为发送方;保持每日发送频率稳定,不要发垃圾内容 |
| 某些rss源始终抓取不到 | 源已失效或反爬严格 | 用curl手动访问源地址看返回状态码;尝试更换抓取频率;直接删除该源或替换为备用源 |
| 邮件正文全是html源码 | 邮件客户端不支持该类型 | 确认发送时content-type设置的是 text/html 而不是 text/plain ;不要用 =="alternative" 的写法 |
| 汇总信息里的日期比别人慢一天 | 时区未设置 | 在脚本开头设置 tz 环境变量并调用 time.tzset() ;检查服务器系统时区 |
| 中文摘要乱码 | 编码未统一 | 确保rss解析后统一转成utf-8;邮件主题用header编码;html模板里声明字符集 |
| 邮件发重复了 | 同一篇文章被多个rss源转载 | 在聚合阶段对文章链接做去重,按url的hash作为唯一标识 |
4.2 去重策略:多源转载的处理
说到去重这里想展开讲一下,因为这是我实际运行中遇到的最频繁的问题。科技新闻领域,同一件事常常被多家媒体报道,有的文章是转载,有的是深度跟进,标题不同但内容高度相似。如果不去重,你的邮件里会出现同一个产品新闻被四个源各报道一遍的情况,非常影响阅读体验。
我的方案比较简单——对url做规范化后计算hash。每抓取一篇文章,就把它的链接去掉 utm_* 等追踪参数,利用 urllib.parse 解析并重新拼接url,然后计算md5值放入一个集合。新文章加入集合前先检查这个hash是否已存在,重复的直接丢弃。不过这个方案只对“完全相同的链接”有效,对“不同链接但内容相同”的识别需要用到文本相似度计算,成本较高,这个项目中我没做,而是通过限制每个源的条目数来降低重复率。
4.3 日志系统的设计
日志是这个项目的“眼睛”,没有日志,你很难定位问题到底出在哪个环节。我在代码里设置了两个日志级别: info 记录每次任务的开始、完成的抓取源数量、发送结果; warning 和 error 记录抓取失败、解析异常、发送失败等异常情况。日志文件按天切割,保留最近30天,避免磁盘被 日志占满。
用到的日志配置很简洁,就是python标准库logging加上一个每天轮转的 timedrotatingfilehandler :
import logging
from logging.handlers import timedrotatingfilehandler
def setup_logger():
logger = logging.getlogger("digest_bot")
logger.setlevel(logging.info)
handler = timedrotatingfilehandler(
"logs/digest.log", when="midnight", backupcount=30
)
formatter = logging.formatter("%(asctime)s - %(levelname)s - %(message)s")
handler.setformatter(formatter)
logger.addhandler(handler)
return logger
这样之后,排查问题时只需要打开当天的日志文件,就能看到完整的执行时间线和具体的报错信息。我甚至给日志加了简单的统计逻辑,在每天邮件发送成功后输出一行关键信息,包含抓取到的文章总数、去重后保留的数量、摘要生成成功的数量、邮件发送状态,这样一眼就能判断整个流水线有没有“带病运行”。
5. 项目扩展方向与后续优化
5.1 从“摘要”到“定向关注”的演进
基础版本上线运行稳定后,我开始考虑怎么把它变得更“聪明”。目前它是完全被动的聚合器——抓什么源、推什么内容,全靠我提前配置。但实际的阅读需求是分场景的:周一早上我需要看上周的融资收购汇总,周三下午我可能更关注ai领域的新论文或新产品发布。于是我在源码里预留了关键词过滤的开关,运行脚本时可以通过命令行参数传入今天的关注主题,比如:
python3 main.py --topics "ai, 芯片, 新能源"
脚本在聚合阶段会把包含这些关键词的文章权重调高,让它们出现在邮件列表的更靠前位置。如果你有明确的领域偏好,比如只关心aigc或者只关心新能源车,这个功能可以让你从一大堆泛科技新闻里快速筛选出真正关心的部分。
这个功能的实现也不复杂。在生成摘要和分组排序的时候,给每篇文章加一个主题相关度分数,计算方式是标题和摘要中命中关键词的次数加权,排序时优先按主题分数降序排列。这样不需要改动既有架构,就能让邮件内容更加个性化。
5.2 替代方案对比:rss阅读器与第三方简报服务
如果你不想自己维护全套代码,也有几条省事的替代路线可以对比。inoreader和feedly这类专业rss阅读器本身就带有邮件摘要推送功能,你可以直接在上面订阅科技新闻源,设置每日摘要邮件。这条路线的优点是完全不用写代码,缺点是摘要的定制化程度低,邮件排版也受平台限制。
还有一类服务叫“新闻简报生成器”,典型的如cortex、daily.dev等,它们主打开发者新闻和周报。cortex的摘要质量很高,但收费不便宜,而且你没法控制它抓取哪些源。与其付这份钱,不如花一个下午把本项目的代码跑起来。自建方案的长期成本几乎为零,控制力和灵活性反而是最高的。
5.3 数据可视化与多维度分析
最后的扩展方向是对文章的归档数据做分析。我每天运行的脚本会在本地生成一个json文件,记录当天抓取到的所有文章。积累一段时间之后,这些数据可以用来回答很多有趣的问题:这周科技圈最热的高频词是什么?哪些新闻源的首发速度最快?某家公司在过去一个月的曝光趋势如何?如果你有数据可视化的需求,可以把这些json数据导到grafana或者直接用python的matplotlib画图,做成一个“科技新闻热力看板”。
不过这个属于锦上添花的功能,项目前期没必要做。先把“每日准时收到一封可读性高的邮件”这个主流程跑通,比什么都强。
做这个项目到现在,最深的体会是:很多工具的“效率”其实是被高估的,真正折腾人的不是写代码,而是决定“什么该看、什么不该看”的信息筛选过程。自动摘要邮件机器人的价值不在于替你读新闻,而在于帮你把“获取信息”这个动作的边际成本降到足够低,让阅读重新回到“主动选择”而不是“被动刷屏”。如果你也被每天上百条科技资讯淹没,不妨抽一个周末试试把这套东西搭起来。最后分享一个小技巧:邮件发送时间不要定得太晚,放在早高峰之前效果最好,我自己调到7点之后,邮件打开率明显比一开始的9点高出一大截。
以上就是基于python编写一个新闻自动摘要邮件机器人的详细内容,更多关于python摘要邮件机器人的资料请关注代码网其它相关文章!
发表评论