Automating sending bulk emails from an excel file

Viewed 76

Email Notification List

I want to automatically send custom/personalized emails to school parents on my list as seen in the image above, giving details of the students' course, and other relevant info.To do that, I am using openpyxl and smtplib modules.

However, my looping through the rows and items in my dictionaries bearing student information and parent information isn't working well. Every time I run the script, I get this type of error

Traceback (most recent call last):
  File "class_email_notification.py", line 42, in <module>
    for course, account, link, clasS_day, session in class_info.items():
ValueError: not enough values to unpack (expected 5, got 2)

Both my xlsx and .py files are located in the same directory. Snippet of .py file is this:

import openpyxl, smtplib, sys, datetime
from time import sleep

wb = openpyxl.load_workbook('course_notification.xlsx')
sheet = wb['student info']

parents = {}
class_info = {}
students = {}
day = datetime.datetime(2020, 6, 1, 8, 0 ,0).strftime('%A, %B, %d, %Y %I:%M:%S %p')

for r in range(2, sheet.max_row + 1):
    parent_name = sheet.cell(row = r, column = 8).value
    parent_email = sheet.cell(row = r, column = 9).value
    parents[parent_name] = parent_email

    course = sheet.cell(row = r, column = 3).value
    account = sheet.cell(row = r, column = 4).value
    link = sheet.cell(row = r, column = 5).value
    clasS_day = sheet.cell(row = r, column = 6).value
    session = sheet.cell(row = r, column = 7).value
    class_info[course] = account, link, clasS_day, session

    gender = sheet.cell(row = r, column = 2).value
    student_name = sheet.cell(row = r, column = 1).value

smtpObj = smtplib.SMTP('smtp.gmail.com')
smtpObj.ehlo()
smtpObj.starttls()

for parent_name, parent_email in parents.items():
    for course, account, link, clasS_day, session in class_info.items():
        smtpObj.login('example@gmail.com', sys.argv[1])
        if gender.lower() == 'male':
            gender = 'his'
            body = 'Subject: Tinker Education Online Classes\n\nDear %s,\n\nHope you and your family are doing well and keeping safe while at home. Tinker Education would like to bring to your attention that our online classes will commence  on ', day,' .\n\nOur teachers would like to have an insanely great start of the term with our students. Hence, you are requested to notify your child of ',gender, 'class time. Class details are as follows:\n\n%s\n\nDay: %s\nSession: %s\nCLP:\n%s\nVideo link: %s\n\n%s is requested to keep time of ', gender, ' %s %s\n\nKind regards,\nTinker Desk'%(parent_name, course, clasS_day, session, account, link, student_name, course, session)
        else:
            gender = 'her'
            body = 'Subject: Tinker Education Online Classes\n\nDear %s,\n\nHope you and your family are doing well and keeping safe while at home. Tinker Education would like to bring to your attention that our online classes will commence  on ', day,' .\n\nOur teachers would like to have an insanely great start of the term with our students. Hence, you are requested to notify your child of ',gender, 'class time. Class details are as follows:\n\n%s\n\nDay: %s\nSession: %s\nCLP:\n%s\nVideo link: %s\n\n%s is requested to keep time of ', gender, ' %s %s\n\nKind regards,\nTinker Desk'%(parent_name, course, clasS_day, account, session, link, student_name, course, session)
        print('Sending emails to %s through %s'%(parent_name, parent_email))
        send_email_status = smtpObj.sendmail('my_email@gmail.com', parent_email, body)

if send_email_status != {}:
    print('There was an error sending an email to %s through %s'(parent_name, parent_email))
smtpObj.quit()

My for loop while iterating through the keys and values in the dictionaries do not provide enough values to unpack. What am I missing?

I have tried to understand why all items in the dicts cannot be fetched. My assumption is that my logic is not so correct.

I have made reference to Automate the boring stuff: sending emails, and I can understand how to go about it. But really knowing the exact logic as to why the dicts on my script do not entirely unpack is my issue.

1 Answers

The structure returned from iterating through class_info.items() is a nested tuple here, where the first element is the key and the second element is the associated value. In this case, it's (account, link, clasS_day, session).

You could get this to work in its current form by using: for course, (account, link, clasS_day, session) in class_info.items():

i.e. replicating the tuple structure returned by class_info.items()

Related