Search code examples
pythonpandascsvsslsmtplib

I don't understand why I get a "too many values to unpack" error


When I run this I can get it to ask me for my password but when it start my "for" loop, I get a error regrading my data.

import csv, smtplib, ssl
import pandas as pd 


newhire = pd.read_csv('New_Hires_Test.csv', delimiter = ",", skiprows=7)   #Open up the document and 
skip header

newhire["Email"] = "test@gmail.com"     #Add a row 'Email' and add email address

mask = newhire["New IT Item"] == "New"      #brings back only new in "New IT Item column"

message = """\Subject: {Effective Date}
From: test@gmail.com
To: test@gmail.com 

Hello IT, 

We have a new user by the name of {StartDate}. The new user will be starting on {Employee} and will 
be working at {PC}. 
Their title will be {Title} and their supervisor is {Supervisor}"""

from_address = "test@gmail.com"
password = input("Type your password and press enter: ")


context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
    server.login(from_address, password)

    for Employee, StartDate, PC, Title, Supervisor, Email in newhire[mask]:
        server.sendmail(
            from_address,
            Email,
            message.format(Employee=Employee, StartDate=StartDate, PC=PC, Title=Title, Email=Email, 
Supervisor=Supervisor)
        )

print('Emails were sent successfully!')

***ValueError: too many values to unpack (expected 6)***

I'm looking at my "for" loop and I see that have 6 columns that I am looking for. My data is all strings and I set up a delimiter just to make sure that all of the data is separated properly.I think I am just either overlooking the issue or not understanding my data.

****New_Hires_Test.csv***
Report:  ,,,All HR Action Requests: IT CAFs - New Hires (KB 
Copy),,,,,,,,,,,,,
Sorted By:  ,,,Effective Date Descending,,,,,,,,,,,,,
Filtered By:  ,,,Initiator Filter: All Employees; Employee Filter: All 
Employees; Approver Filter: All Employees; HR Action = Hire Employee (Staff) 
- Step 2,,,,,,,,,,,,,
Date & Time:  ,,,01/06/2020 09:12p,,,,,,,,,,,,,
Generated By:  ,,,Haywood,,,,,,,,,,,,,
Company:  ,,,Corp Solutions(6122261),,,,,,,,,,,,,
,,,,,,,,,,,,,,,,
New IT Item,StartDate,Effective Date,Employee Name,PC,Title,Supervisor 
Name,Manager 2 Name,O365,ID 
Badge,Computer,Avionte,GP,Hotspot,Tablet,TimeZone,HR Action
New,01/13/2020,02/03/2020,Elizabeth Anne Everts,Internal Staff/003 - 
003,Onboarding Specialist,Suzanne Mitchell,Angela 
Robbins,Yes,,No,Yes,No,No,No,Eastern,Hire Employee (Staff) - Step 2
New,01/13/2020,01/13/2020,Karla Ramirez,Internal Staff/204 - 003, 
Recruiter,Scott Clark,Shane Houser,Yes,,Standard 
Laptop,Yes,Yes,No,No,Central,Hire Employee (Staff) - Step 2
New,01/13/2020,01/06/2020,Megan Arreola,Internal Staff/221 - 
003,Recruiter,Elsa Muneton,Amanda Stewart,Yes,,No,Yes,No,No,No,Eastern,Hire 
Employee (Staff) - Step 2

Solution

  • Replace you for loop with iterrows() call as below:

            for i, r in newhire[mask].iterrows():
                server.sendmail(
                    from_address,
                    r["Email"],
                    message.format(Employee=r["Employee"],
                       StartDate=r["StartDate"],
                                   PC=r["PC"],
                                   Title=r["Title"],
                                   Email=r["Email"], 
                                   Supervisor=r["Supervisor"]
                    )
                )
    
    

    EDIT1:

    newhire[mask] in for a,....,c in newhire[mask] will unpack the contents of newhire[mask] int a,....,c ( the whole dataframe ). What you want to do is unpack the contents of only a single row. In order to do that you can use newhire[mask].iterrows() which, on every row returns its index and the row instance itself.

    You can also use itertuples() as described in this question Pandas for loop over dataframe gives too many values to unpack