Python Forum
Email Security with SendGrid - what are the risks?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Email Security with SendGrid - what are the risks?
#1
Hi,

I download a bunch of documents on a monthly basis and then mail them out to specific individuals. I wrote a code to automate the process using import os and import sendgrid. To use sendgrid, I have typed in the API Key into the program. My IT team is saying that "it's not a great practice for API credentials to be stored without proper procedure/process for encryption / security". What kind of security do I need and why?

I am an accountant and I don't have the technical background to understand the risks associated with sending emails using sendgrid. Can someone give a risk assessment of my code? I am trying to understand what could go wrong IF THE CODE WORKS. Please see below for the code (modified of course to omit sensitive details).

#First we imoprt modules. the base64 is imported to encode the attachments
#datetime is imported so we can calculate the due date
#os module can redirect file path of where the documents (before renaming) are kept. 
#SendGrid module is for the emailing
import base64
import datetime
import os
import sendgrid
from sendgrid.helpers.mail import *
#once the modules are imported, create the dictionaries for looking up how to rename files
#   to whom the documents will be sent, how to decipher how the statement should be named, etc
#
#the nd {} converts the last 4 digits of the document number to receipient's initials, their First name, and their email address
#the mDict{} converts the long date string in "YYYYMMDD" format by breaking down the month in "Mmm" and year in "YYYY" format



nd = {
            '1111':['BB','Bruce','[email protected]'],
            '2222':['CK','Clarke','[email protected]'],
            '3333':['BA','Berry','[email protected]'],
            '4444':['HJ','Hal','[email protected]'],
        }
#the change directory focuses the code at a specific folder. the whole program is designed to run on ALL FILES 
# within the specified direcotry. this means that if the directory is not changed and left to Downloads or Documents for instance
# the program will try to rename every single file within download folder or documents folder. So, it is crucial to change this directory to
# somewhere that only contains the documents
#notice that the directory path is denoted with double \. this is because a single \ denotes line continuation in python. so 
# D O   N O T   F O R G E T   T O change the \ to \\
os.chdir('C:\\Users\\Joker\\Documents\\Python\\importantDocs')

mDict = {
    '01':'Jan', '02':'Feb', '03':'Mar',
    '04':'Apr', '05':'May', '06':'Jun',
    '07':'Jul', '08':'Aug', '09':'Sep',
    '10':'Oct', '11':'Nov', '12':'Dec'
}


# simple datetime calculation to add +14 days to today. 14 days is 10 business days + 4 weekend days. 
tday = datetime.date.today()
TenBusnDays = datetime.timedelta(days=14)
dueDate = tday + TenBusnDays


# Loop starts. 

for f in os.listdir():
        fileName, fileExt = (os.path.splitext(f))
        Stmt, cardEnd, date = (fileName.split('_'))
        rEmail = nd[cardEnd][2]
        rName = nd[cardEnd][1]
        cardEnd = nd[cardEnd][0]
        year = date[0:4]
        date = mDict[date[4:6]]
        newName = '{} - {} {}{}'.format(cardEnd, date, year, fileExt)

# below is a print statement for testing if the files will be renamed correctly. # out the next line (the os.rename line) when testing. 
        #print(newName, '--->', rName, '--->', rEmail,'--->','--->',date,'--->',year)
        os.rename(f, newName)
    
#------------------------------------------------------------------------------------------------------------|
#                                                                                                            |
#                                                                                                            |
#             At this point the files have been renamed. the next bit of code pertains to emailing.          |
#                                                                                                            |
#                                                                                                            |
#------------------------------------------------------------------------------------------------------------|



#email body in HTML format. Be careful if passing non-string variables. Python won't concatenate non-string variables. so pass them under str()
        email_body="""<p><span style="color: #000080;">Hi """ + rName + """,<br>Here's the super duper important file for """ + date + """ """ + year + """.<br> 
        Please give this page turner a read by """ + str(dueDate.strftime("%b %d, %Y")) + """. Please send me your comments as soon as possible. If you would like to discuss in person, I am happy to accomodate.<br>
        <br>Thank you.</p></span>"""

#email parameters setup: Mail (from, to, subject, content)
#attachment is not an object that can be passed under Mail function. This is done separately below.

        from_email = Email("[email protected]")
        to_email = To(rEmail)
        subject = "Super duper important document for " + date + ' ' + year
        content = Content("text/html", email_body)
        mail = Mail(from_email, to_email, subject, content)

#encoding and attaching file. 

        with open(newName, 'rb') as g:
            data = g.read()
            g.close()
        encoded_file = base64.b64encode(data).decode()

#the filetype is not really necessary.

        attachedFile = Attachment(
            FileContent(encoded_file),
            FileName(newName),
            FileType('application/pdf'),
            Disposition('attachment')
        )
        mail.attachment = attachedFile

        sg = sendgrid.SendGridAPIClient(api_key='blahblahblahblah123412340234randomCharacterSequence')
        response = sg.client.mail.send.post(request_body=mail.get())
        print(response.status_code, response.body, response.headers)
Reply
#2
The api-key could be stored in a local file and should not appear in code.
Other field like from could be defined in a config file.

Then you could share your code without editing it every time before you send it.

To improve the security, you could additionally encrypt the e-mails with gpg, but this requires the receiver to have public/private key-pair and you need the public key from them.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#3
Normally, code is stored in version control repositories. So things like api keys, database passwords, etc you don't want in the code, because you don't want it visible in the repository. Instead, you'd have a config file outside the repository, that you then load and use. json is built into python, so something like:
import json

config = {}
with open("../../config.json") as f:
    config = json.load(f)

sendgrid_api_key = config["sendgrid_api_key"]
And your config file would look something like:
{
  "sendgrid_api_key": "asdf234asdfew",
  "email_from_address": "[email protected]"
}
Then the config file would be backed up in a secure place, outside the code storage, where only a few people have access. Perhaps a "secrets" bucket on aws s3, for example.
Reply
#4
DeaD_EyE and nilamo, Thank you very much. From both your answers, my understanding is that not storing the key in a secure file is the issue. The emails being sent out themselves cannot be tampered with by anyone outside (generally speaking). And as long as the API Key is stored in a secure location where it cannot be accessed without permission, I should be reasonably safe in sending these emails.

Thanks again for your help!
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020