So I'm trying to create an automated email script that reads surnames, recipient emails, and files to be attached from an excel file.
For some reason, when I send the email with the attachments it returns a KeyError, which I think traces back to the placeholder for the filename of the attachment that I'm using .add_header('Content-Disposition', 'attachment; filename = {file}')
with. Because whenever I change the placeholder, the KeyError specifies what I wrote in it.
Anyways, here's the source code
import pandas as pd
import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
context = ssl.create_default_context()
sender = '[email protected]'
sender_pass = '123456789'
email_subject = 'subject'
attachments_list = 'testingemail.xlsx'
body = 'Dear Mx. {surname} body'
def attach_attachment(attachment_list, payload):
# opening excel file into dataframe
attachments = pd.read_excel(attachment_list, sheet_name = 'attachments')
for file in attachments['attachments']:
with open(file, 'rb') as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part) # encoding attachment
part.add_header(
'Content-Disposition',
'attachment; filename = {file}',
)
# attaching attachment
payload.attach(part)
def composing_email(e_sender, e_password, e_subject, e_recipient, attachment_list):
# setup the MIME
message = MIMEMultipart()
message['From'] = e_sender
message['To'] = e_recipient
message['Subject'] = e_subject
# attaching body and the attachments for the mail
message.attach(MIMEText(body, 'plain'))
attach_attachment(attachment_list, message)
# create SMTP session for sending the mail
session = smtplib.SMTP('smtp.gmail.com', 587) # gmail port
session.starttls(context = context) # securing connection
session.login(e_sender, e_password) # logging into account
text = message.as_string()
# actually sending shit
session.sendmail(e_sender,
e_recipient,
text.format(surname = surname,
receiver_email = recipient,
sender = e_sender,
)
)
session.quit()
print('Mail successfully sent to {surname} with emal {recipient}')
if __name__ == '__main__':
surname_email = pd.read_excel('testingemail.xlsx', sheet_name = 'surname_email')
for surname, recipient in surname_email.itertuples(index=False):
composing_email(sender, sender_pass, email_subject, recipient, attachments_list)
and here's the error
Traceback (most recent call last):
File "c:\Users\zddj9\Desktop\auto_email\script.py", line 77, in <module>
composing_email(sender, sender_pass, email_subject, recipient, attachments_list)
File "c:\Users\zddj9\Desktop\auto_email\script.py", line 64, in composing_email
text.format(surname = surname,
KeyError: 'file'
CodePudding user response:
I just realized that I needed to use f-string formatting
instead of this
part.add_header(
'Content-Disposition',
'attachment; filename = {file}',
)
add an f
before the argument with the placeholder
part.add_header(
'Content-Disposition',
f'attachment; filename = {file}',
)
The confirmation also wouldn't work without f-string formatting
print('Mail successfully sent to {surname} with email {recipient}')
It should be this
print(f'Mail successfully sent to {surname} with email {recipient}')