patternpythonMinor
Python code to encrypt and email PDF file using PyPDF2
Viewed 0 times
fileemailandpypdf2pythonusingcodeencryptpdf
Problem
This is my first programming project with real world application. It's purpose is to take a file from a directory, encrypt it with a predetermined password, and email to appropriate recipient.
ID Email and Password are found in a CSV file that I created EmailDict from.
ID and Filename are parsed and dropped into FileDict. Any feedback is valued and appreciated.
```
import os
import re
import csv
import PyPDF2
import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
# Create a dictionary with the csv values for ID, Email and Password
EmailDict = dict()
with open('commissionrepemaillist.csv', 'r') as infile:
reader = csv.reader(infile)
for row in reader :
REP = row[0]
EMAIL = row[1]
PASSWORD = row[2]
EmailDict[REP] = EMAIL, PASSWORD
# create dictionary of IDs and Pdf Files
FileDict = dict()
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1"
for FILE in os.listdir(path):
split = re.split("[_.]", FILE)
ID = split[1]
FileDict[ID] = FILE
# encrypt PDF files in FileDict based on ID and Password from EmailDict
for ID in FileDict:
if ID in EmailDict:
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1\\"
file = os.path.join(path + FileDict[ID])
inputStream = PyPDF2.PdfFileReader(file)
output = PyPDF2.PdfFileWriter()
output.appendPagesFromReader(inputStream)
output.encrypt(EmailDict[ID][1])
with open(file, 'wb') as outputStream:
output.write(outputStream)
else : continue
# email encrypted pdf file to appropriate rep
for ID in FileDict:
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1\\"
file = os.path.join(path + FileDict[ID])
with open(file, 'rb') as pdf :
pdfAttachment = MIMEApplication(pdf.read(), _subtype = 'pdf')
ID Email and Password are found in a CSV file that I created EmailDict from.
ID and Filename are parsed and dropped into FileDict. Any feedback is valued and appreciated.
```
import os
import re
import csv
import PyPDF2
import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
# Create a dictionary with the csv values for ID, Email and Password
EmailDict = dict()
with open('commissionrepemaillist.csv', 'r') as infile:
reader = csv.reader(infile)
for row in reader :
REP = row[0]
EMAIL = row[1]
PASSWORD = row[2]
EmailDict[REP] = EMAIL, PASSWORD
# create dictionary of IDs and Pdf Files
FileDict = dict()
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1"
for FILE in os.listdir(path):
split = re.split("[_.]", FILE)
ID = split[1]
FileDict[ID] = FILE
# encrypt PDF files in FileDict based on ID and Password from EmailDict
for ID in FileDict:
if ID in EmailDict:
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1\\"
file = os.path.join(path + FileDict[ID])
inputStream = PyPDF2.PdfFileReader(file)
output = PyPDF2.PdfFileWriter()
output.appendPagesFromReader(inputStream)
output.encrypt(EmailDict[ID][1])
with open(file, 'wb') as outputStream:
output.write(outputStream)
else : continue
# email encrypted pdf file to appropriate rep
for ID in FileDict:
path = "C:\\Apps\\CorVu\\DATA\\Reports\\Monthly Commission Reports\\Output\\pdcom1\\"
file = os.path.join(path + FileDict[ID])
with open(file, 'rb') as pdf :
pdfAttachment = MIMEApplication(pdf.read(), _subtype = 'pdf')
Solution
Your code is easy enough to follow. All of your
Your variables — such as
Speaking of
I doubt that there is any value in writing all of those encrypted versions of the files to disk. You could just create a transient encrypted copy in memory, mail it off, and move on to the next recipient. To accomplish that, you can write to a
The code to encrypt the PDF and compose the mail message feels like it could belong logically together. I'd define a function for that:
Your code would be more expressive if you defined the dictionary entries "all at once" using a dict comprehension. I would also avoid storing the e-mail and password as a tuple, since it makes you write more cryptic code like
I think that you would be better off not defining
open() calls are done using with blocks, which is a good habit.Your variables — such as
REP and EmailDict — are unconventionally named. Use ALL_CAPS for constants, and lower_case for variables. Ironically, the one variable that should be a constant, path, is defined several times, and not written as a constant.Speaking of
path, you are misusing os.path.join(). The whole point of the function is to ensure that the path delimiter is automatically inserted for you between the components. So, you should write os.path.join(path, FileDict[ID]) instead. Also, use raw strings to make your backslashes less cumbersome.I doubt that there is any value in writing all of those encrypted versions of the files to disk. You could just create a transient encrypted copy in memory, mail it off, and move on to the next recipient. To accomplish that, you can write to a
StringIO object instead of a file.The code to encrypt the PDF and compose the mail message feels like it could belong logically together. I'd define a function for that:
def message_for(unencrypted_pdf_path, rep_id, email, password):
"""
Creates a MIME message for a rep containing an encrypted version
of the specified PDF.
"""
buf = StringIO()
…
encrypted_pdf = buf.getvalue()
text = MIMEText(… % rep_id)
pdf_attachment = MIMEApplication(encrypted_pdf, _subtype='pdf')
pdf_attachment.add_header('content-disposition', 'attachment', filename=('MonthlyPaidCommission_%s.pdf' % rep_id))
msg = MIMEMultipart(_subparts=[text, pdf_attachment])
msg['SUBJECT'] = 'Commission Report'
msg['FROM'] = 'me'
msg['TO'] = rep['EMAIL']
return msgYour code would be more expressive if you defined the dictionary entries "all at once" using a dict comprehension. I would also avoid storing the e-mail and password as a tuple, since it makes you write more cryptic code like
EmailDict[ID][1] later.I think that you would be better off not defining
FileDict at all. Just process each directory entry as you encounter it. You can even send multiple messages within the same SMTP connection. Just make sure you keep a log of what was sent, in case something goes wrong.PATH = r'C:\Apps\CorVu\DATA\Reports\Monthly Commission Reports\Output\pdcom1'
COLS = ['rep_id', 'email', 'password']
with open('commissionrepemaillist.csv', 'r') as infile:
email_dict = {
row[0]: dict(zip(COLS, row)) for row in csv.reader(infile)
}
smtp = smtplib.SMTP('localhost:587')
smtp.starttls()
smtp.login(…)
for filename in os.listdir(PATH):
rep_id = re.split('[_.]', filename)[1]
rep = email_dict.get(rep_id)
if rep is None:
continue
msg = message_for(os.path.join(PATH, filename), *rep)
smtp.sendmail('me', rep['email'], msg.as_string())
print("Sent %s to %s" % (filename, rep['email']))
smtp.quit()Code Snippets
def message_for(unencrypted_pdf_path, rep_id, email, password):
"""
Creates a MIME message for a rep containing an encrypted version
of the specified PDF.
"""
buf = StringIO()
…
encrypted_pdf = buf.getvalue()
text = MIMEText(… % rep_id)
pdf_attachment = MIMEApplication(encrypted_pdf, _subtype='pdf')
pdf_attachment.add_header('content-disposition', 'attachment', filename=('MonthlyPaidCommission_%s.pdf' % rep_id))
msg = MIMEMultipart(_subparts=[text, pdf_attachment])
msg['SUBJECT'] = 'Commission Report'
msg['FROM'] = 'me'
msg['TO'] = rep['EMAIL']
return msgPATH = r'C:\Apps\CorVu\DATA\Reports\Monthly Commission Reports\Output\pdcom1'
COLS = ['rep_id', 'email', 'password']
with open('commissionrepemaillist.csv', 'r') as infile:
email_dict = {
row[0]: dict(zip(COLS, row)) for row in csv.reader(infile)
}
smtp = smtplib.SMTP('localhost:587')
smtp.starttls()
smtp.login(…)
for filename in os.listdir(PATH):
rep_id = re.split('[_.]', filename)[1]
rep = email_dict.get(rep_id)
if rep is None:
continue
msg = message_for(os.path.join(PATH, filename), *rep)
smtp.sendmail('me', rep['email'], msg.as_string())
print("Sent %s to %s" % (filename, rep['email']))
smtp.quit()Context
StackExchange Code Review Q#111635, answer score: 4
Revisions (0)
No revisions yet.