#萌新日志#1.Python脚本:文件根据学号批量发送到对应的邮箱

        萌新记录某些日子的学习经历。

前言:

        老师中午给我发了批改后的实验报告(.pdf),作为教师助理我需要把每份报告返还给对应的学生,还需要登记成绩。一个学期5+次报告,50+位学生,使用学校系统发送邮件,过程太繁琐了,要耗费很多时间精力。写一个脚本应该方便不少。

        每一份报告pdf文件名都会出现学号,并且我们学校邮箱也是学号+后缀的统一格式。所以我确定了初步思路:遍历文件名,获取学号,编辑好邮件内容发送给对应学号的学生。作为这方面的萌新,请教了学长后得到肯定答复,于是有了以下内容。

摘要:Python 脚本 邮件 os re smtplib MIMEText MIMEMultipart MIMEApplication

以下是具体实现过程:

目录

使用os遍历文件

使用re获取文件名中的学号

发送邮件

Result

Whole Code

Reference       


使用os遍历文件

import os

path = "./" + labName
files = os.listdir(path)
print(type(files),len(files))
for filename in files:

需要使用os,os模块提供了非常丰富的方法用来处理文件和目录。[1]

os.listdir(path) 返回path指定的文件夹包含的文件或文件夹的名字的列表。

        比如说我的代码的绝对路径是E:\A_scriptTools\dspMail,我保存文件的绝对路径是E:\A_scriptTools\dspMail\demo,文件保存为E:\A_scriptTools\dspMail\demo\*。此时我path是demo这个文件夹。这个函数返回的值是一个存储string的list。每个string是每个文件的名字,包括后缀。

        至此我们得到了每个PDF文件的名字。


使用re获取文件名中的学号

pattern = "Lab2 Report_(.*?)_.*?"

def getSID(filename):
    information = re.match(pattern, filename)
    SID = information.group(1)
    return SID

        需要使用re,正则表达式是一个特殊的字符序列,它能帮助我们方便的检查一个字符串是否与某种模式匹配。[2]

re.match(pattern, string, flags=0)

        pattern是需要匹配的正则表达式,string是要匹配的字符串。flag标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

        比如我这里:

         其中"11111111"是学号,"Lab 2 Report_" 和学号后的"_"是固定不变的。那么我的pattern设置为

pattern = "Lab2 Report_(.*?)_.*?"

         .*? 可以视为任意字符串。返回的值是一个group(如果不存在这样格式的是none)。group[0]表示在string中找到的完整的pattern。group[i]表示需要替换第i个(.*?)(要有括号)的内容。比如说:

#萌新日志#1.Python脚本:文件根据学号批量发送到对应的邮箱_第1张图片

         这里group[1]就是需要的学号。


发送邮件

        从思路上来说发送邮件需要三个部分:设置参数(需要各种参数,包括host,用户名,密码,发送地址和接收地址,发送时间等等)、编辑邮件内容(主要包括正文和附件)、发送邮件(发送邮件这个过程需要先“登录邮箱”,并且还要确保发送这个过程是顺利的)。

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication

        需要借助两个包:

        smtplib是关于 SMTP(简单邮件传输协议)的操作模块,在发送邮件的过程中起到服务器之间互相通信的作用[3]。用于登录邮箱、把编辑好的邮件发送出去。

        三个3来自email.mime.*的工具用于编辑邮件(后缀大概能看出各自的作用):

        MIMEMultipart可以说是粘合剂、框架。有了这个粘合剂,那么正文和附件都能往上填。

        MIMEText主要用于处理文本信息,正文一般用这个来生成。

        MIMEApplication是我用来处理PDF文件的。

        那么代码实现如下,

        1. 首先输入参数:

mail_host = 'smtp.exmail.qq.com'
my_sender = 'XXXX'
my_pass = 'xxxx'
receiver = SID + '@mail.XXX.edu.cn'

        mail_host我这里是使用的腾讯企业邮箱,值得注意的:1.腾讯企业邮箱的登录密码不是邮箱密码,而是客户端密码。需要在网页版腾讯企业邮箱中打开:“设置-邮箱绑定-安全设置:开启安全登录”,如果不这样做,用smtplib登录腾讯企业邮箱没办法突破人工验证那一关,会报错:535, b'Error: authentication failed, system busy。2.腾讯企业邮箱需要 SSL 认证,所以我之后的代码会是SMTP_SSL,有的邮箱不需要SSL使用SMTP就好。详情请看Reference中知乎那篇专栏,写的比我好。

        senderreceiver分别表示发送地址和接收地址。

        2. 接下来,编辑邮件内容        

    message = MIMEMultipart()
    message['From'] = my_sender
    message['To'] = receiver
    message['Subject'] = labName + ' 报告结果'
    part1 = MIMEText('这是批改后的报告,请您查收。祝好。', 'plain', 'utf-8')

    part2 = MIMEApplication(open(file, 'rb').read())
    part2.add_header('Content-Disposition', 'attachment', filename=labName+'-'+SID+'.pdf')

    message.attach(part1)
    message.attach(part2)

        新建一个messageFrom表示发件地址,To表示收件地址,Subject表示标题,part1是正文,Part2是对应的PDF文件。注意正文和PDF文件所调用的函数都有参数需要输入。需要根据实际情况调整。最后使用message.attach装入正文和附件。

        3. 最后,发送邮件

    try:
        smtpObj = smtplib.SMTP_SSL(mail_host, port=465)
        smtpObj.login(my_sender, my_pass)
        smtpObj.sendmail(
            my_sender, receiver, message.as_string())
        smtpObj.quit()
        print(SID + ' success')
    except smtplib.SMTPException as e:
        print(SID+'error', e)

        如前文所说,腾讯企业邮箱需要SMTP_SSL,端口号是465,不同邮箱最好先查询一些具体端口号。

        login登录邮箱,sendmail发送编辑好的邮件,最后quit退出邮箱。


Result:

       大概流程以上,附实际效果图:

#萌新日志#1.Python脚本:文件根据学号批量发送到对应的邮箱_第2张图片

#萌新日志#1.Python脚本:文件根据学号批量发送到对应的邮箱_第3张图片

        总结一下,都是很基础的工具。一个文件夹装好PDF文件,定位到路径用os读文件名;初步分析学号位置,用re在字符串中找到学号;email.mime.*写邮件,包括邮件标题、收件人、发件人,正文和附件需要各自创建好后组合在一起。用smtplib发邮件,登录-发送-登出,登录需要账号密码以及不被安全检测阻拦。

        (By the way听说yagmail更适合python?

        感谢阅读,请多指教!


Whole Code

import os
import re
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication

labName = ""
pattern = ""
mail_host = ''
my_sender = ''
my_pass = ''


def getSID(filename):
    information = re.match(pattern, filename)
    SID = information.group(1)
    return SID

def sendEmail(SID, file):
    receiver = SID + '@mail.XXX.edu.cn'

    ## PDF
    message = MIMEMultipart()
    message['From'] = my_sender
    message['To'] = receiver
    message['Subject'] = labName + ' 报告结果'
    part1 = MIMEText('这是批改后的报告,请您查收。祝好。', 'plain', 'utf-8')

    part2 = MIMEApplication(open(file, 'rb').read())
    part2.add_header('Content-Disposition', 'attachment', filename=labName+'-'+SID+'.pdf')

    message.attach(part1)
    message.attach(part2)
    try:
        smtpObj = smtplib.SMTP_SSL(mail_host, port=465)
        smtpObj.login(my_sender, my_pass)
        smtpObj.sendmail(
            my_sender, receiver, message.as_string())
        smtpObj.quit()
        print(SID + ' success')
    except smtplib.SMTPException as e:
        print(SID+'error', e)


def sendPDF(labName):
    path = "./" + labName
    files = os.listdir(path)
    print(type(files),len(files))
    for filename in files:
        SID = getSID(filename)
        print(SID)
        sendEmail(SID,path+'/'+filename)

if __name__ == "__main__":
    sendPDF(labName)

Reference       

[1] Python OS 文件/目录方法 | 菜鸟教程 (runoob.com) 

[2] Python 正则表达式 | 菜鸟教程 (runoob.com) 

[3] 简单三步,用 Python 发邮件 - 知乎 (zhihu.com) 

[4] Python 简单发送邮件 / 发送带各种附件邮件_zqzwzd的博客-CSDN博客_python发送邮件带附件 

感谢学长的帮助 手动@郭山车 (7条消息) guo_hao_rui的博客_郭山车_CSDN博客-数据科学中的统计分析领域博主

你可能感兴趣的:(python,os,正则表达式,smtp)