Commit 7f1e52fa authored by Olivier's avatar Olivier
Browse files

Module 12: send grades to students

The code in this commit is contributed by Germán Santa Maria.
parent 42a19403
# -*- coding: utf-8 -*-
"""
Author: German Santa Maria
Script: Email Grades
Description: This script can be used to send personalized emails with grades
for the students that participated in the peer-graded assignments.
Input:
1 - grade_to_send.csv :
This file contains the data from the students including their custom ID
and email adresses and grades.
2 - All the pdf files with the solution for the students
for example: “Solution_submisison_1_A12345678.pdf”
Output:
1 - sent_emails.csv : file with the log of the sent emails
"""
"""-------------------------Hard coded input--------------------------------"""
# Input files paths
input_csv_path = 'script_input/grades_to_send.csv'
solutions_pdfs_path = 'script_input/'
# Output files paths
output_csv_path = 'script_output/sent_emails.csv'
# (Hard-coded email settings)
host="myhost.example.com"
port = 587
sender_email = "sender@example.com"
sender_username = "username"
cc = "cc_address@example.com"
password = input("Type your password and press enter:")
# Email delay time (in seconds)
# For example set delay_time >240 seconds (less than 30 emails/hour)
# Inside OVGU network set delay_time >40 seconds (less than 30 emails/10 min)
delay_time = 45
"""-------------------------------------------------------------------------"""
# Import email sender function
import csv # For reading cvs files
import pathlib # For working with local paths
import smtplib, ssl # For email
import time # For timer
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# Initialize arrays to store data
names = [] # Student name
last_name = [] # Student last name
emails = [] # Student email address
custom_ID_A = [] # Custom ID of the assignment for the student
custom_ID_G = [] # Custom ID of the grading file for the student
attachments = [] # Name of the attachment for each student
email_bodies = [] # Body of the email for each student
text_emails = [] # Array with the complete email text for each student
email_log = [] # Array with the log of successfully sent emails
peer1_grade1 = []
peer1_grade2 = []
peer1_grade3 = []
peer1_grade4 = []
peer1_grade5 = []
peer1_grade6 = []
peer1_rem_poits = []
peer1_final_grade = []
peer2_grade1 = []
peer2_grade2 = []
peer2_grade3 = []
peer2_grade4 = []
peer2_grade5 = []
peer2_grade6 = []
peer2_rem_poits = []
peer2_final_grade = []
avg_grade = []
# Store students data from csv file into variables
with open(input_csv_path, newline='') as f:
student_info_reader = csv.reader(f)
next(student_info_reader) # Skip header [name, last name, email, ...]
student_data = [row for row in student_info_reader]
for row in student_data:
custom_ID_A.append(row[0])
custom_ID_G.append(row[1])
names.append(row[4])
last_name.append(row[5])
emails.append(row[6])
peer1_grade1.append(row[7])
peer1_grade2.append(row[8])
peer1_grade3.append(row[9])
peer1_grade4.append(row[10])
peer1_grade5.append(row[11])
peer1_grade6.append(row[12])
peer1_rem_poits.append(row[13])
peer1_final_grade.append(row[14])
peer2_grade1.append(row[15])
peer2_grade2.append(row[16])
peer2_grade3.append(row[17])
peer2_grade4.append(row[18])
peer2_grade5.append(row[19])
peer2_grade6.append(row[20])
peer2_rem_poits.append(row[21])
peer2_final_grade.append(row[22])
avg_grade.append(row[23])
for ID in custom_ID_A:
attachment_name = "Solution_submisison_1_"+ID+".pdf"
attachments.append(attachment_name)
# Make sure that all the attachments are in the script_input folder
for i in range(0, len(custom_ID_A)):
file_to_search = pathlib.Path(solutions_pdfs_path+attachments[i])
if file_to_search.exists() != True:
raise Exception('The file ' +
solutions_pdfs_path+attachments[i]+
' was not found, no emails were sent')
"""-----------------Build email text for each student-----------------------"""
# Write a personalized email body for each student
standard_body = """Dear XXstudent_nameXX,
thank you for grading your peers on this coursework assignment!
Two of your peers graded your work over the week-end. You obtained an average of XXavg_grade2XX / 10 for this assignment. I attach the complete solution to your work, as well as your submisison, so you may compare.
The details of the grades are as follows:
Peer 1:
Q1 Is the correct general formula for the answer provided? XXpeer1_grade1XX
Q1 Is the correct corresponding calculation provided? XXpeer1_grade2XX
Q1 Is a sensible final result provided, expressed with the correct units? XXpeer1_grade3XX
Q2 Is the correct general formula for the answer provided? XXpeer1_grade4XX
Q2 Is the correct corresponding calculation provided? XXpeer1_grade5XX
Q2 Is a sensible final result provided, expressed with the correct units? XXpeer1_grade6XX
Points removed because the submission is poorly formatted or poorly organized XXpeer1_rem_poitsXX
Peer 2:
Q1 Is the correct general formula for the answer provided? XXpeer2_grade1XX
Q1 Is the correct corresponding calculation provided? XXpeer2_grade2XX
Q1 Is a sensible final result provided, expressed with the correct units? XXpeer2_grade3XX
Q2 Is the correct general formula for the answer provided? XXpeer2_grade4XX
Q2 Is the correct corresponding calculation provided? XXpeer2_grade5XX
Q2 Is a sensible final result provided, expressed with the correct units? XXpeer2_grade6XX
Points removed because the submission is poorly formatted or poorly organized XXpeer2_rem_poitsXX
As you can see, the average of both grades is XXavg_grade2XX / 10 points
(insert email body)
with best regards,
(author)
"""
for i in range(0, len(names)):
temp_body = standard_body.replace("XXstudent_nameXX", names[i])
temp_body = temp_body.replace("XXpeer1_grade1XX", peer1_grade1[i])
temp_body = temp_body.replace("XXpeer1_grade2XX", peer1_grade2[i])
temp_body = temp_body.replace("XXpeer1_grade3XX", peer1_grade3[i])
temp_body = temp_body.replace("XXpeer1_grade4XX", peer1_grade4[i])
temp_body = temp_body.replace("XXpeer1_grade5XX", peer1_grade5[i])
temp_body = temp_body.replace("XXpeer1_grade6XX", peer1_grade6[i])
temp_body = temp_body.replace("XXpeer1_rem_poitsXX", peer1_rem_poits[i])
temp_body = temp_body.replace("XXpeer1_final_gradeXX", peer1_final_grade[i])
temp_body = temp_body.replace("XXpeer2_grade1XX", peer2_grade1[i])
temp_body = temp_body.replace("XXpeer2_grade2XX", peer2_grade2[i])
temp_body = temp_body.replace("XXpeer2_grade3XX", peer2_grade3[i])
temp_body = temp_body.replace("XXpeer2_grade4XX", peer2_grade4[i])
temp_body = temp_body.replace("XXpeer2_grade5XX", peer2_grade5[i])
temp_body = temp_body.replace("XXpeer2_grade6XX", peer2_grade6[i])
temp_body = temp_body.replace("XXpeer2_rem_poitsXX", peer2_rem_poits[i])
temp_body = temp_body.replace("XXpeer2_final_gradeXX", peer2_final_grade[i])
temp_body = temp_body.replace("XXavg_grade2XX", avg_grade[i])
email_bodies.append(temp_body)
# Compose email text for each student
for i in range(0, len(names)):
# Reciever email
receiver_email = emails[i]
# Email subject
subject = "Insert subject here"
# Email body
body = email_bodies[i]
# Attachment
filename = attachments[i]
# Set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Cc"] = cc
# Add body to email
message.attach(MIMEText(body, "plain"))
# Add attachment
attachment_path = solutions_pdfs_path + filename # Attachment folder path
# Open PDF file in binary mode
with open(attachment_path, "rb") as attachment:
# Add file as application/octet-stream
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",
f"attachment; filename= {filename}",)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
text_emails.append(text)
"""-------------------------------------------------------------------------"""
# Send an email to each student with the corresponding attachment
"""------------------------------Send emails--------------------------------"""
# Create a secure SSL context
context = ssl.create_default_context()
# Check if the login data is correct
try :
server = smtplib.SMTP(host = host, port = port)
server.starttls(context = context) #Encryption
server.login(sender_username, password)
print('Login to: '+ sender_email + ' was successful ')
except Exception as e:
# Print error message
print('Login to: '+ sender_email +
' was not successful, no emails were sent ')
raise Exception(e)
server.close() # Logout
# Send email to each student
for i in range(0, len(names)):
try :
# Reciever email
receiver_email = emails[i]
# Email content
text = text_emails[i]
# Logging into OVGU email server
server = smtplib.SMTP(host = host, port = port)
server.starttls(context = context) #Encryption
server.login(sender_username, password)
# Send email
server.sendmail(sender_email, [receiver_email, cc], text)
# Logout
server.close() # Logout
# Print email log
local_time = time.time()
time_sent = time.ctime(local_time)
log_m = 'Email was sent to: ' + receiver_email + ' time: ' + time_sent
print(log_m)
except Exception as e:
# Print error
log_m = 'Error while trying to send email to: ' + receiver_email
print(log_m)
print(e)
log_m = 'Email could not be sent, error: ' + str(e)
# Save log
email_log.append(log_m)
# Wait before sending the next email
time.sleep(delay_time)
# Store email log in a csv file
with open (output_csv_path,'w',newline='') as f:
writer = csv.writer(f)
writer.writerow(['name','lastname','email','custom_ID_A','custom_ID_G',
'log'])
for i in range(0,len(names)):
writer.writerow([names[i],last_name[i],emails[i],custom_ID_A[i],
custom_ID_G[i], email_log[i]])
"""-------------------------------------------------------------------------"""
# End of the script
#!/bin/bash
# Input parameters
inputfolder='script_input-real'
outputfolder='script_output-real'
timestamp=$(date "+%Y-%m-%d+%H%M%S")
outputbackupname="backup_output_$timestamp.tar"
inputbackupname="backup_input_$timestamp.tar"
# Create archive of output folder
mkdir -vp archives
tar -cvf $outputbackupname --exclude=old $outputfolder
mv -vf $outputbackupname archives/
tar -cvf $inputbackupname --exclude=old $inputfolder
mv -vf $inputbackupname archives/
# Import output of M11 into input of M12
rsync -avh --delete ../M11_generate_graded/done/ $inputfolder/pdfs/
# Clear output folder
rm -rvf $outputfolder/*
echo "end of script."
......@@ -56,5 +56,5 @@ A total of 12 modules (9 of which being locally-run scripts) are needed to run t
[x] [Module 11](M11_generate_graded): Generate graded PDFs
(in bash, with pdftk)
[ ] Module 12: Send results to students
[x] [Module 12](M12_email_graded): Send results to students
(in Python)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment