I needed to find a way to send email reports from a scheduled cron job. I looked for a simple linux command-line email solution but couldn’t find anything that fitted the bill. I was already using Django’s EmailMessage class in an existing app, so I started to think about how I could re-use it for scheduled jobs.
I’m using linux in this scenario, but it would probably work fine in Windows too.
First I configured my cron job (actually the .sh script that cron job runs) to output to a file called report.txt. This would be overwritten each time the job ran, so would always be the latest version.
An existing Django project settings.py had the following settings to enable email sending via a Gmail (or Google Apps) account. The settings are based on Nathan Ostgard’s Gmail and Django article.
EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = 'user@domain.com' EMAIL_HOST_PASSWORD = 'password' EMAIL_PORT = 587 EMAIL_USE_TLS = True
So I knocked up a standalone python script sendreport.py that would take these settings and email the report.txt file to me.
#!/user/bin/python
#
# Get settings from an existing django project
import sys
import os
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '/..'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'my_django_project.settings'
from django.core.mail import EmailMessage
# Set up email fields
recipient = 'myemail@mydomain.com'
subject = 'CRON Job Report'
body = 'CRON Job Report for blah, blah, blah . . .'
# Create email object, attach file, send
email = EmailMessage(subject, body, to = [recipient])
email.attach_file('report.txt')
email.send()
The EmailMessage class makes it very easy to attach a file and send the email. I can tag this on to the end of the .sh script executed by the cron job and jobs-a-good-un
Well sort of . . it’s functional, but not ideal. It works by reading email settings from an existing Django app’s setting.py. I wanted it to be more portable, and not dependent on a specific Django configuration/app.
Then I found out that you can specify Django settings from within a standalone python script. Could this method be used to break any dependencies and make the script more portable? Absolutely!
#!/user/bin/python
#
# Configure some standalone django settings
# These settings are for a gmail or google apps account
from django.conf import settings
settings.configure (
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'user@domain.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
)
from django.core.mail import EmailMessage
import datetime
import sys
import socket
# Get the hostname and current time to put in the email
hostname = socket.gethostname()
timestamp = datetime.datetime.now().ctime()
# Set up email fields
recipient = 'myemail@mydomain.com'
subject = '%s CRON Job Report: %s' % (hostname, timestamp)
body = 'Report for %s on %s attached' % (hostname, timestamp)
# Create email object, attach file, send
email = EmailMessage(subject, body, to = [recipient])
email.attach_file('bkp_report.txt')
email.send()
I also made use of hostname()and datetime() to provide some more detail for the email subject and body.
Now the only dependency is Django itself – which I’m happy with, my job reports are archived in email – which I like, and I get to use more Python – which is good for me.
