An interesting challenge that I faced today. I wanted to create a CSV file on my Django project (fairly easy, huh) and email it as attachment. My first challenge was to save the file in a temp directory that is OS independent since I do my development on Windows and the application runs on a linux server. I came across this really cool python module called tempfile, but the drawback to me for using this module was that:
- It would create these random filenames
- I didn’t want to have the recipient see a random filename and think of it as spam
- The files would stay in the temp directory until manually cleaned up. Since the files need to be attached after creations, I didn’t want to delete them after creation which is the default behavior for tempfile (s)
So, the solution I found was to use tempfile module to get the location of the temp directory. Then use that location and write a file using standard I/O with a specific name. Every time the job runs, it would overwrite the old file and I won’t have a ton of files sitting in the temp directory. Here’s the complete solution to the problem:
from datetime import datetime, timedelta import csv import tempfile, os file_path = os.path.join(tempfile.gettempdir(), 'expired_deployments.csv') email_from = "YOUR-EMAIL@DOMAIN.COM" email_to = ["TO-EMAIL@DOMAIN.COM"] email_subject = "YOUR EMAIL SUBJECT" email_body = "YOUR EMAIL BODY..." # Create CSV file f = open(file_path, 'wb') file_writer = csv.writer(f, quotechar='"', quoting=csv.QUOTE_MINIMAL) # Write headers to CSV file file_header = ['Product Type', 'Company Name', 'SFID', 'DeploymentID', 'Status', 'License Expiration', 'Support Expiration'] file_writer.writerow(file_header) file_writer.writerow(['XYZ', 'ABC In.c', 12345, 123, 'Active', '5/31/2017', '12/31/2017']) f.close() # Read the file and send as attachment fr = open(f.name, "rb") mail = CustomEmailMessage(email_subject, email_body, email_from, to=email_to, bcc=) mail.attach(os.path.basename(f.name), fr.read(), "application/octet-stream") mail.send() fr.close()
Note: The piece of code that sends out the email only works on Django. If you’re looking to send a file using standard python libraries, check out this other article about using smtplib to send out email attachments.
Here’s the custom class CustomEmailMessage that overrides that Django class EmailMessage. This is useful to stop email messages going out to actual users when you’re working on a development system. Must always use CustomEmailMessage to send out email notification and it would take care of things.
from django.core.mail.message import EmailMessage class CustomEmailMessage(EmailMessage): # Over writting the send function so that in development and eval mode, emails are not sent to all. def send(self, fail_silently=False): """Sends the email message.""" if settings.ENVIRONMENT == 'development' or settings.ENVIRONMENT == 'eval': # Staging's settings is same as production. self.to = [self.from_email,] if not self.recipients(): # Don't bother creating the network connection if there's nobody to # send to. return 0 return self.get_connection(fail_silently).send_messages([self])