一、前言
闲暇之余,想给身边的朋友每天定时发送问候,本来想调微信来实现的,但由于微信处于安全考虑,已将网页授权登录关闭;
所以就想着用邮箱代替来实现一个每日关爱脚本 !!!
下面我们先看一下效果,如图;
好文章 记得收藏+点赞+关注额 !!!---- Nick.Peng
二、关爱邮件效果图
- 大概邮件信息以及格式如下,大家可以根据各自的需求微调;
三、发送关爱邮件实现步骤
- 项目依赖
- Python版本:python3
- 第三方包:requests、apscheduler
3.1、获取天气方法
-
定义一个每日关爱邮件类;
-
定义实例属性,下面会用到;
-
定义获取天气信息的方法,详情如下,每个步骤都有备注,很容易懂;
- 调用实例属性天气API;
- 提取周信息、天气状况、最低最高气温、风向、风力、感冒预警关爱信息;
- 制定邮件天气模版并填充以上提取的信息;
class DailyGreeting(object): """ 每日邮件关爱 """ def __init__(self): self.cb_link = 'http://open.iciba.com/dsapi/' # 金山词霸api提供的每日一句 self.whether_link = 'http://wthrcdn.etouch.cn/weather_mini?city=' # 天气api def get_whether(self, city): """ 获取天气信息 :param city: 城市 :return: msg """ url = self.whether_link + city r = requests.get(url).json() week = r['data']['forecast'][0]['date'][-3:] # 周几 weather = r['data']['forecast'][0]['type'] # 天气 low_temp = r['data']['forecast'][0]['low'][3:] # 最低气温 high_temp = r['data']['forecast'][0]['high'][3:] # 最高气温 wind_dir = r['data']['forecast'][0]['fengxiang'] # 风向 wind_force = r['data']['forecast'][0]['fengli'][9:-3] # 风力 warn = r['data']['ganmao'] # 感冒预提醒 # 填充天气信息模板 msg = '<br>亲爱的朋友,' + '今天 ' + week + '<br>' + \ '<br><font size=3 color=#0081ff><strong>天气:</strong></font>' + city + ' ' + weather + \ '<br><font size=3 color=#0081ff><strong>温度:</strong></font>' + low_temp + '~' + high_temp + \ '<br><font size=3 color=#0081ff><strong>风向:</strong></font>' + wind_dir + ',' + wind_force + \ '<br><br><font size=3 color=red><strong>注意:</strong></font>' + warn + '<br>' return str(msg)
3.2、获取词霸每日一句方法
-
定义get_word方法,并调用实例属性词霸每日一句API;
-
提取中英文每日一句;
-
制定邮件每日一句模版并填充以上提取的信息;
def get_word(self): """ 获取金山词霸每日一句 :return: msg """ r = requests.get(self.cb_link).json() en = r['content'] cn = r['note'] indent = ' ' \ ' ' # 填充每日一句模板 msg = '<br><font size=3 color=lightpink><strong><i>' + en + '<br>' + cn + '</strong></font><br>' + \ '<br>' + indent + '<font size=3 color=#a5673f>—— 最关心你的人儿~' + \ '<br><html><body><img src={}></body></html>'.format(r['fenxiang_img']) return str(msg)
3.3、发送邮件方法
-
指定发件人邮件地址和登录授权码;
-
创建一个邮件对象,并指定邮件主题,发件人,收件人等;
-
创建邮件客户端对象,连接邮箱服务器地址,登录认证,并调用sendmail发送邮件,发送完毕断开邮箱服务连接;
@staticmethod def send_email_message(email, message): """ 完成发送邮件功能 :param email: 收件人 :param message: 邮件发送内容 :return: """ # 发件人邮箱地址 sender = 'xxxxxxx@163.com' # 客户端授权码:需要在注册邮箱后,登录进入->设置->常规设置->客户端授权码 里面进行设置 auth_code = 'SISQXKZBXVBDADASD' messageObj = MIMEText(message, "html", "utf-8") # 设置主题 messageObj['Subject'] = Header("每日温馨提醒!", "utf-8") # 设置发件人 messageObj['From'] = sender # 设置收件人 messageObj['To'] = email try: # 建立客户端 smtpObj = smtplib.SMTP() # 连接163邮箱服务器地址 smtpObj.connect('smtp.163.com') # 方法二:服务器上建议使用SSL的方式创建连接, 因为阿里云服务器为了安全起见默认屏蔽25号端口 # smtpObj = smtplib.SMTP_SSL('smtp.163.com', 465) # smtpObj.ehlo() # 使用EHLO向ESMTP服务器标识自己 # 登录认证 smtpObj.login(sender, auth_code) # 发送邮件 smtpObj.sendmail(sender, [email], messageObj.as_string()) # 断开连接 smtpObj.close() print("Send mail successfully.") return True except smtplib.SMTPException as e: print("Send email failed.") print("Error logs: ", e) return False
3.4、调度方法实现
-
对调用传递的好友练习方式进行遍历,并调用send_email_message分别发送邮件;
def main(self, friend_list): """ 调度方法 :return: Boole """ for friend in friend_list: mail = friend.get('mail') city = friend.get('city') cur_whether = self.get_whether(city) cur_word = self.get_word() # 构造邮件的正文内容 msg = '您的贴心小秘上线啦 !!!<br>' + cur_whether + cur_word print("=========={}: {}".format(friend.get('mail'), msg)) self.send_email_message(mail, msg)
3.5、定时任务实现
-
方法一:使用 apscheduler 定时任务框架
import traceback from apscheduler.schedulers.blocking import BlockingScheduler try: # 初始化一个阻塞式调度器 scheduler = BlockingScheduler() daily_greeting = DailyGreeting() # 添加定时任务:每天8点执行一次 scheduler.add_job(daily_greeting.main, 'cron', day='*', hour=8, args=friend_list) scheduler.start() except Exception as e: print(e) traceback.format_exc()
-
方法二:自定义定时任务
SECONDS_PER_DAY = 24 * 60 * 60 # 一天时间(秒) SET_TIME = 7 # 定时每日7点执行一次 is_first = True # 是否第一次执行任务 now = datetime.datetime.now() # 第一次执行获取当前时间 # 定时执行任务逻辑 while True: cur_s = now.hour * 60 * 60 + now.minute * 60 + now.second # 当前时间(时+分+秒)--> 秒 first_gap_s = 0 # 第一次等待的时间(秒) if now.hour > SET_TIME: # 当前时间小时数 大于 7点 first_gap_s = 24 * 60 * 60 - cur_s + SET_TIME * 60 * 60 # 差距 --> 秒 elif now.hour < SET_TIME: # 当前时间小时数 小于 7点 first_gap_s = SET_TIME * 60 * 60 - cur_s if is_first: # 第一次执行需要等待的时间,即first_gap_s秒后调用main()发送邮件 time.sleep(first_gap_s) else: time.sleep(SECONDS_PER_DAY) # 每24H执行一次 DailyGreeting().main(friend_list) is_first = False # 第一次执行完后将is_first置False
四、完整源代码
-
同学们期待的完整源码来啦 !!!赶紧撸下来吧。
^o^ ~ ^o^
-
有了它,我们就可以将其上传到服务器,使用以下命令运行即可实现每日给亲朋好友发送邮件啦;
-
后台运行命令:
nohup python3 Send_greeting.py >message.out 2>&1 &
-
在这里顺便 送大家 一套2020最有趣的Pyhon项目实战视频教程,视频地址: 点击进去就能免费拿,希望大家一起进步!
# -*- coding: utf-8 -*- # @Author: Nick # @Last Modified by: Nick # @Last Modified time: 2020-03-31 16:21:36 import time import datetime import requests import smtplib from email.mime.text import MIMEText from email.header import Header import traceback from apscheduler.schedulers.blocking import BlockingScheduler class DailyGreeting(object): """ 每日邮件关爱 """ def __init__(self, friend_list): self.cb_link = 'http://open.iciba.com/dsapi/' # 金山词霸api提供的每日一句 self.whether_link = 'http://wthrcdn.etouch.cn/weather_mini?city=' # 天气api self.friend_list = friend_list def get_whether(self, city): """ 获取天气信息 :param city: 城市 :return: msg """ url = self.whether_link + city r = requests.get(url).json() week = r['data']['forecast'][0]['date'][-3:] # 周几 weather = r['data']['forecast'][0]['type'] # 天气 low_temp = r['data']['forecast'][0]['low'][3:] # 最低气温 high_temp = r['data']['forecast'][0]['high'][3:] # 最高气温 wind_dir = r['data']['forecast'][0]['fengxiang'] # 风向 wind_force = r['data']['forecast'][0]['fengli'][9:-3] # 风力 warn = r['data']['ganmao'] # 感冒预提醒 # 填充天气信息模板 msg = '<br>亲爱的朋友,' + '今天 ' + week + '<br>' + \ '<br><font size=3 color=#0081ff><strong>天气:</strong></font>' + city + ' ' + weather + \ '<br><font size=3 color=#0081ff><strong>温度:</strong></font>' + low_temp + '~' + high_temp + \ '<br><font size=3 color=#0081ff><strong>风向:</strong></font>' + wind_dir + ',' + wind_force + \ '<br><br><font size=3 color=red><strong>注意:</strong></font>' + warn + '<br>' return str(msg) def get_word(self): """ 获取金山词霸每日一句 :return: msg """ r = requests.get(self.cb_link).json() en = r['content'] cn = r['note'] indent = ' ' \ ' ' # 填充每日一句模板 msg = '<br><font size=3 color=lightpink><strong><i>' + en + '<br>' + cn + '</strong></font><br>' + \ '<br>' + indent + '<font size=3 color=#a5673f>—— 最关心你的人儿~' + \ '<br><html><body><img src={}></body></html>'.format(r['fenxiang_img']) return str(msg) @staticmethod def send_email_message(email, message): """ 完成发送邮件功能 :param email: 收件人 :param message: 邮件发送内容 :return: """ # 发件人邮箱地址 sender = 'xxxxxxx@163.com' # 客户端授权码:需要在注册邮箱后,登录进入->设置->常规设置->客户端授权码 里面进行设置 auth_code = 'SISQXKZBXVBDADASD' messageObj = MIMEText(message, "html", "utf-8") # 设置主题 messageObj['Subject'] = Header("每日温馨提醒!", "utf-8") # 设置发件人 messageObj['From'] = sender # 设置收件人 messageObj['To'] = email try: # 建立客户端 smtpObj = smtplib.SMTP() # 连接163邮箱服务器地址 smtpObj.connect('smtp.163.com') # 方法二:利用SSL的方式发送 # smtpObj = smtplib.SMTP_SSL('smtp.163.com', 465) # smtpObj.ehlo() # 使用EHLO向ESMTP服务器标识自己 # 登录认证 smtpObj.login(sender, auth_code) # 发送邮件 smtpObj.sendmail(sender, [email], messageObj.as_string()) # 断开连接 smtpObj.close() print("Send mail successfully.") return True except smtplib.SMTPException as e: print("Send email failed.") print("Error logs: ", e) return False def main(self): """ 调度方法 :return: Boole """ for friend in self.friend_list: mail = friend.get('mail') city = friend.get('city') cur_whether = self.get_whether(city) cur_word = self.get_word() # 构造邮件的正文内容 msg = '您的贴心小秘上线啦 !!!<br>' + cur_whether + cur_word print("=========={}: {}".format(friend.get('mail'), msg)) self.send_email_message(mail, msg) print("========== 每日华丽分割线 ==========") if __name__ == '__main__': # 需要发送邮件的联系方式 friend_list = [{'mail': '2911111111@qq.com', 'city': '郑州'}] # DailyGreeting(friend_list).main() try: # 初始化一个阻塞式调度器 scheduler = BlockingScheduler() daily_greeting = DailyGreeting(friend_list) # 添加定时任务:每天8点执行一次 scheduler.add_job(daily_greeting.main, 'cron', day='*', hour=8) scheduler.start() except Exception as e: print(e) traceback.format_exc()