Postmark, Django, Webfaction and CSV Attachments

If your Django site sends emails and they are getting blocked, you might want to consider using Postmark. These are my notes for getting it to work on Webfaction.

On Postmark, you need to create a sender signature. This involves setting up DKIM and SPF on Webfaction. To setup SPF, go to the Webfaction control panel and select the domain name for your web site. This will pull up a panel that will allow you to add a DNS record. When you create the Postmark signature, it gave you text for the SPF record. Postmark says to add it as a TXT record. On Webfaction, I got it to work adding it as a SPF record. When that is done, click verify on Postmark. The first time I did this, it took several hours before verify would work.

Postmark also gave you a DKIM domain name and TXT. On Webfaction, create that domain name, select DNS record TXT and paste in the text from Postmark. Pretty straight forward, except the first time I did this, it took about 12 hours before Postmark could verify this record. That’s a long time to wait when you are not sure you did it right.

**** Jan 2015 Update*************************************

Below, I describe how to use Postmark with Django using the Postmark API. Now you can skip the API and use Postmark’s SMTP server. I tried it and it works. Here are the Django settings:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST_PASSWORD = 'my Postmark Server API key'  # From Postmark credentials field
EMAIL_HOST_USER = 'my Postmark Server API key'  # this is intentionally repeated
EMAIL_PORT = '587'  # encrypted
SERVER_EMAIL = 'my server email address, setup on Postmark'

***** End Jan 2015 Update ********************************

To get things working in Django, install python-postmark. I installed version 0.4.2 using:

pip install python-postmark

Add these lines to your Django settings file:

EMAIL_BACKEND = 'postmark.django_backend.EmailBackend'
POSTMARK_API_KEY     = 'my api key'

Here is a view for testing email:

from django.http import HttpResponse
from django.core.mail import send_mail
from django.conf import settings

def sendmail_test(request):
    to = ['the email address']
    send_mail('the subject', 'test message', settings.DEFAULT_FROM_EMAIL, to, fail_silently=False)
    return HttpResponse('Mail was sent to %s' % to[0])

Sending a CSV file was a little more tricky. I thought I could send it as a text file. But when I tried,  got this error:

PMMailUnprocessableEntityException: u'Unprocessable Entity: Invalid attachment content - illegal base64 string.

Base 64 encoding of the CSV file solved that problem:

import csv
import base64

from django.http import HttpResponse
from django.core.mail import EmailMessage
from django.conf import settings

def sendmail_test_w_attachment(request):
    """Send mail with attachment
    # Make csv file
    filename = 'test.csv'
    fp = open(filename, 'wb')
    writer = csv.writer(fp)
    writer.writerow(['data 1', 'data 2'])
    writer.writerow([1, 2])

    to = ['to email address']
    email = EmailMessage('TimeSheet CSV File', 'The CSV is attached.',  to=to)

    # Load file and Base64 encode csv data
    data = open(filename, 'rb').read()
    encoded = base64.b64encode(data)
    email.attach('test.csv', encoded, mimetype='application/octet-stream')

    # Send it

    return HttpResponse('Mail was sent to %s' % to[0])

Important Note

Postmark works from the development server (, so you can do all your tests before going live.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s