小组要求每周五下班前要发送周报,但是我每次都忘记,虽然Foxmail邮箱能设置提醒,但还是想自己写个脚本来实现相关功能。
主要功能:每周五晚上7点提醒我发送周报邮件。
主要思路:
1. 发送邮件
最开始想到的当然是怎么用Python把邮件发送出去了,用的是yagmail库。首先安装yagmail库
pip install yagmail
以QQ邮箱为例:
import yagmail
# 登录你的邮箱
yag = yagmail.SMTP(user = '[email protected]', password = 'xxx', host = 'smtp.qq.com')
# 发送邮件
yag.send(to = ['[email protected]','[email protected]'], subject = '邮件的主题', contents = ['我要发送的内容', 'C://Users//Desktop//log.txt', 'C://Users//Desktop//music.txt'])
只需要三行代码即可发送邮件,分别看下登录邮箱和发送邮件的方法:
# 登录邮箱
yagmail.SMTP(user, password, host, port)
user:你的邮箱
password:授权码或密码,自行百度如何获取QQ邮箱授权码,我公司用的是Foxmail,所以这里我填的是我的邮箱密码
host:发件服务器,不同邮箱的服务器不同
port:服务器端口,QQ邮箱可不填
我用公司邮箱的时候还有一个坑:我填了以上4个参数后,提醒我STARTTLS extension not supported by server,原来是我公司的服务器不支持STARTTLS,所以在port参数后加上了smtp_starttls = False即可
# 发送邮件
yag.send(to, subject, contents, attachments, cc)
to:收件人,可以用列表的方式支持多个收件人,[‘[email protected]’, ‘[email protected]’]
subject:邮件主题
contents:邮件内容
attachments:附件,也可以跟我前面一样,将附件和内容写在一个列表里,也可以分开写。附件也支持用列表的方式表示多个附件。
cc:抄送
2. 弹框提醒
这部分我是用pyqt5写了两个UI界面,一个是提醒框,一个是写邮件的界面。逻辑是到了指定的时间弹出提醒框
提醒框的代码:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QInputDialog, QLineEdit, QTextEdit, QGridLayout, QHBoxLayout, QVBoxLayout, QFileDialog, QMessageBox
from PyQt5.QtCore import QCoreApplication, Qt, QThread
from PyQt5.QtGui import QFont
#提醒框
class AlertWeekly(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 从(600, 300)位置开始,显示一个300*100的界面
self.setGeometry(600, 300, 300, 100)
self.setWindowTitle('写周报')
#设置窗口总是在最前面
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.label = QLabel('兄弟,该写周报了!', self)
self.label.move(30, 20)
self.label.setFont(QFont('楷体', 20, QFont.Bold))
self.btnCertain = QPushButton('好的', self)
self.btnCertain.move(60, 60)
self.btnCancel = QPushButton('不写', self)
self.btnCancel.move(170, 60)
self.btnCancel.clicked.connect(self.closeDialog)
def closeDialog(self):
self.close()
当然还是先需要下载pyqt5的库,pyqt5基本跟qt的方法一样,比较简单,碰到不懂的函数直接百度就行了。
简单的介绍下用到的几个函数:
setGeometry(400, 100, 600, 500):第一个和第二个参数是横坐标和纵坐标,决定了该界面在屏幕的位置,第三个和第三个参数是该界面的宽高
setWindowTitle():设置UI界面的名字,显示在左上角
setWindowFlags(Qt.WindowStaysOnTopHint):设置该UI界面总是显示在最前面,比如说你正在看网页,如果没有设置该属性,就会被网页遮挡,你都不知道弹出了提醒框
点击“好的”,弹出写邮件界面,点击“不写”则直接退出
写邮件界面的代码:
class WriteWeekly(QWidget):
def __init__(self):
super().__init__()
self.initUI()
# 嵌套布局
def initUI(self):
self.setGeometry(400, 100, 600, 500)
self.setWindowTitle('发送邮件')
#需要使用嵌套布局,整体是垂直布局(网格布局+水平布局),水平布局放两个按钮
self.wwg = QWidget(self)
self.wlayout = QVBoxLayout(self.wwg)
self.creatGridLayout()
self.createHLayout()
self.wlayout.addLayout(self.grid)
self.wlayout.addLayout(self.hlayout)
self.setLayout(self.wlayout)
# 网格布局
def creatGridLayout(self):
self.grid = QGridLayout()
self.receiverLabel = QLabel('收件人:', self)
self.receiverEdit = QLineEdit(self)
self.subjectLabel = QLabel('主题:', self)
self.subjectEdit = QLineEdit(self)
self.fileLabel = QLabel('附件:', self)
self.fileBtn = QPushButton('选择文件', self)
self.fileBtn.clicked.connect(self.selectFile)
self.contentLabel = QLabel('内容:', self)
self.contentEdit = QTextEdit(self)
self.receiverEdit.setFont(QFont('Microsoft YaHei UI', 11))
self.subjectEdit.setFont(QFont('Microsoft YaHei UI', 11))
self.contentEdit.setFont(QFont('Microsoft YaHei UI', 11))
#设置网格间的距离
self.grid.setSpacing(10)
self.grid.addWidget(self.receiverLabel, 1, 0)
self.grid.addWidget(self.receiverEdit, 1, 1)
self.grid.addWidget(self.subjectLabel, 2, 0)
self.grid.addWidget(self.subjectEdit, 2, 1)
self.grid.addWidget(self.fileLabel, 3, 0)
self.grid.addWidget(self.fileBtn, 3, 1)
self.grid.addWidget(self.contentLabel, 4, 0)
self.grid.addWidget(self.contentEdit, 4, 1, 20,1)
# 水平布局
def createHLayout(self):
self.hlayout = QHBoxLayout()
self.sendBtn = QPushButton('发送', self)
self.cancelBtn = QPushButton('取消', self)
self.cancelBtn.clicked.connect(self.close)
self.hlayout.addStretch(3)
self.hlayout.addWidget(self.sendBtn)
self.hlayout.addStretch(1)
self.hlayout.addWidget(self.cancelBtn)
self.hlayout.addStretch(3)
def selectFile(self):
self.filename, _ = QFileDialog.getOpenFileName(self)
self.fileBtn.setText(self.filename)
def showDialog(self):
self.show()
写邮件的界面可能有点复杂,用单个布局可能无法实现,这里使用了嵌套布局,主布局是垂直布局QVBoxLayout,子布局采用网络布局QGridLayout和水平布局QHBoxLayout,嵌套布局的方法见上面的initUI()
点击提醒框,显示写邮件界面,需要先关闭提醒框,然后再显示写邮件窗口,逻辑代码如下:
if __name__ == '__main__':
app = QApplication(sys.argv)
alertDialog = AlertWeekly()
writeDialog = WriteWeekly()
alertDialog.show()
# 确认按钮按下,先关闭提醒窗口,再打开写邮件的窗口
alertDialog.btnCertain.clicked.connect(alertDialog.closeDialog)
alertDialog.btnCertain.clicked.connect(writeDialog.showDialog)
# 发送邮件
writeDialog.sendBtn.clicked.connect(writeDialog.sendEmail)
sys.exit(app.exec_())
读取各输入框里面的内容作为第一部分介绍的发邮件方法的参数,就可以实现发送邮件的功能了。收件人支持多个收件人,采用分号;隔开。
# 读取输入框里的内容
to = self.receiverEdit.text().split(';')
# 主题
subject = self.subjectEdit.text()
# 附件
files = self.fileBtn.text()
# 内容
contents = self.contentEdit.toPlainText()
邮件写完后,点发送即可,发送成功后会弹出发送成功的窗口,并清空所有的输入框,可以再次输入,发送其他邮件
QMessageBox.about(self, '结果', '发送成功')
点击“取消”按钮或者点击右上角的×,会弹出提示框“确认退出吗”,点击确认即可退出
代码如下:
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
3. 定时执行脚本
# 前5个参数分别对应分、时、日、月、星期
0 19 * * 5 /usr/bin/python /home/send_weekly_mail.py
Windows系统
直接百度windows任务计划程序,这里贴一个链接参考
https://yq.aliyun.com/articles/510587
APScheduler库
python有一个很好的定时任务的库,APScheduler库中也实现了类似于linux中的crontab命令。老规矩还是要先安装库。
pip install apscheduler
还是以每周星期五晚上19点为例,详细用法这里就不多介绍了,可以自行百度去看。
from apscheduler.schedulers.blocking import BlockingScheduler
def my_job():
print 'hello world'
sched = BlockingScheduler()
sched.add_job(my_job, 'cron', day_of_week='fri', hour=19, minute=0)
sched.start()
我一开始是用APScheduler库,将上面的my_job方法替换成alertDialog.show,但是在弹出提醒框的时候,发现提醒框未响应,应该是不允许子线程来更新UI,这样会导致未响应,暂时没有好的办法解决这个问题,如果有好的方法用APScheduler库显示UI界面请告诉我,因为sched.add_job必定会开启一个新的子线程来执行,而pyqt5自带的timer只能实现定时多少秒之类的,没办法做到这么精确,所以我最后采用的了windows自带的任务计划程序来执行。
但是以后如果不涉及UI界面,比如我定时去执行一个爬虫,可以采用APScheduler库的方法。
最后完整的代码见我的github,欢迎star。
https://github.com/small-panda/python_script/blob/master/send_weekly_mail.py