[Fixed]-Django – persisting an email to database to be able to send it later?

1πŸ‘

βœ…

I’m going to make a guess based on your can't pickle lock objects message that you may be trying to pickle your objects with the default SMTP connection included.

Try it without it – grepping through the source it is the smtp module that has a self._lock. Pass connection=None to the constructor of the messages.

On Django 1.9, this works for me (Python2):

from django.core.mail import EmailMessage
from django.core.mail import EmailMultiAlternatives
import pickle

email = EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to1@example.com', 'to2@example.com'],
    ['bcc@example.com'],
    reply_to=['another@example.com'],
    headers={'Message-ID': 'foo'},
    connection=None,
)

email.attach("foo", [l for l in open(__file__)], 'text')

print len(pickle.dumps(email))

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to], connection=None)
msg.attach_alternative(html_content, "text/html")

print len(pickle.dumps(msg))

According to the Django code in messages.py, later when you call send() it will attempt to use get_connection() from django.core.mail to get your default connection if EmailMessage.connection is None.

….Alternatively, if you want to use json, this also worked with connection=None:

import json                                                            
print json.dumps(msg.__dict__)                                         
print json.dumps(email.__dict__)

This means you could fairly easily write a JSONEncoder and JSONDecoder to serialize/deserialize your objects as well by basically using the __dict__ of the object.

More on JSON:

As I showed above, encoding the __dict__ makes the encoding easy. You could do msg.__dict__ = json.load(...), but what makes it difficult is the EmailMessage object must be created before you change its values. So you could initialize msg with an EmailMessage that has dummy values, and then assign the __dict__, or decode the JSON and construct the object explicitly by passing the arguments (…and functions) stored in the JSON to the constructor. This requires you to know the internals, though.

I’d go with pickle, although there are security implications.

This SO question covers some other alternatives as well.

πŸ‘€rrauenza

Leave a comment