项目背景※
自动发送邮件是一个很有用的技能,可以为我们的生活带来极大的便利——比如每周的周报写好之后,定时发送给mentor和boss;比如想要第一时间知道某网站的资讯,但是又不想频繁访问网站;比如天气预报有雨雪天气,想睡醒就收到预警;比如发送服务器当天的运行日志,便于晚上查看等等……以上都可以通过自动发送邮件给自己或他人完成,下面做其中一个演示:如果当天天气预报有雨雪等恶劣天气,则发送邮件预警。
需求分析※
- 获取天气预报:获取第二天的天气预报,可通过天气API接口实现。
- 筛选天气条件:筛选出恶劣天气,如果是恶劣天气,才发送邮件预警。
- 定时:每天早上定时执行程序。
- 发送邮件:将邮件发送到指定邮箱,使用SMTP模块发送邮件。
实现步骤※
获取天气预报:选择和风天气API,网站配备了详尽的开发文档可供查阅。
import requests import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import json # 获取天气数据 def get_weather_forecast(api_key, location): url = f'https://devapi.qweather.com/v7/weather/3d?location={location}&key={api_key}' data = requests.get(url).json() result = data['daily'][0] # 可通过GeoAPI查询,例如:curl --compressed "https://geoapi.qweather.com/v2/city/lookup?location=tokyo&key=" city_name_map = { "101060101": "长春", "101280601": "深圳", # "locationID": "city_name" } city_name = city_name_map.get(location, "未知城市") # 默认值为 "未知城市" content = ( f"城市:{city_name} \n" # 动态插入城市名称 f"日期: {result['fxDate']}\n" f"气温: {result['tempMin']}°C~{result['tempMax']}°C\n" f"日间天气: {result['textDay']}\n" f"晚间天气: {result['textNight']}\n" f"日出: {result['sunrise']} 日落: {result['sunset']}\n" f"预报当天总降水量: {result['precip']}mm\n" f"出门记得带伞,路上记得小心!\n" ) return content
筛选天气:只有出现恶劣天气的时候才启动邮件发送。
# 判断是否是坏天气 def is_bad_weather(result): bad_weather_con = ["雨", "雪", "雷"] if any(weather in result['textDay'] for weather in bad_weather_con) or \ any(weather in result['textNight'] for weather in bad_weather_con): return True return False
发送邮件:发送邮件需要开启SMTP功能,不同的邮箱有不同的操作流程,请自行百度,在此不多赘述。
# 发送邮件 def send_email(subject, body, to_email, from_email, smtp_server, smtp_port, login, password): msg = MIMEMultipart() msg['From'] = from_email msg['To'] = to_email msg['Subject'] = subject # 如果传入的 body 是字典类型,将其转换为字符串 if isinstance(body, dict): body = json.dumps(body, ensure_ascii=False, indent=2) # 格式化字典为字符串 # 添加正文内容 msg.attach(MIMEText(body, 'plain')) try: with smtplib.SMTP_SSL(smtp_server, smtp_port) as server: server.login(login, password) server.sendmail(from_email, to_email, msg.as_string()) print(f"Email sent successfully to {to_email}!") except Exception as e: print(f"Failed to send email to {to_email}: {e}")
主函数:
# 主函数 # 替换成自己的数据 def main(): api_key = "" # 城市与邮箱映射,自行添加,如”[email protected]“ city_mail_map = { "长春": [], "深圳": [] } # 城市与locationID映射 city_id_map = { "长春": "101060101", "深圳": "101280601" } # 遍历所有城市 for city, location in city_id_map.items(): to_emails = city_mail_map.get(city, []) # 获取数据 url = f'https://devapi.qweather.com/v7/weather/3d?location={location}&key={api_key}' data = requests.get(url).json() result = data['daily'][0] # 判断天气是否恶劣 if is_bad_weather(result): subject = "今日有雨!" # 邮件配置 from_email = "Bad weather today <[email protected]>" # 以昵称发送邮件 smtp_server = "" #换成对应的服务器地址 smtp_port = 465 login = "" # 换成自己的邮箱 password = "" # 使用应用密码 weather_info = get_weather_forecast(api_key, location) # 发送邮件给每个目标邮箱 for to_email in to_emails: send_email(subject, weather_info, to_email, from_email, smtp_server, smtp_port, login, password) if __name__ == "__main__": main()
定时执行程序:定时执行程序的方式有很多,我选择的是crontab,也就是cron table,它是cron的配置文件,也可以叫作业列表。
# 编辑工作表 crontab -e # crontab的命令构成为 时间+动作,其时间有分、时、日、月、周五种。该命令代表每天5:05执行脚本,*代表分,时,日,月,周 # 具体可以看:https://www.runoob.com/w3cnote/linux-crontab-tasks.html 05 5 * * * /usr/bin/python3 /path/to/script.py
项目补充※
邮箱发送可能不太方便接收,因为有的人不习惯查看邮箱通知。在此提供一个微信消息发送的程序,灵感来源于我用来接收博客通知的极简推送API——server酱,官网:https://sct.ftqq.com/
# 只需要将邮件发送的函数换成下面的函数,再改改主程序的参数即可 # 发送微信消息 def send_wechat_message(content, sckey): """ 发送消息到微信,使用 Server 酱的 API content: 要发送的内容 sckey: Server酱的 SCKEY """ url = f"https://sc.ftqq.com/{sckey}.send" params = { "text": "天气预警", # 消息标题 "desp": content # 消息内容 } data = requests.get(url, params=params) if data.status_code == 200: print("Message sent to WeChat successfully!") else: print(f"Failed to send message to WeChat: {res.text}")
总结※
邮件发送天气预报仅是一个示例,实际上,我们可以通过电子邮件、即时消息、云存储分享等多种方式,传递任何类型的文件或信息。无论是报告、图表、文档还是数据,确保我们能够及时、高效地获取和分享有价值的内容。