Reputation: 1906
In my django project I want to store an email in the database to be able to retrieve it later and send it. I'm implementing a throttling mechanism for sending emails to many users.
I thought it would be as easy as storing 'to, from, subject, body' but then I realized there are attachments, multipart emails, etc, there is at least two classes EmailMessage
and EmailMultiAlternatives
... too many variables and options!
I thought of storing the raw email that one gets with the message()
method, but then not sure how to construct the email back. Also tried pickle
but got can't pickle lock objects
.
Any ideas?
Upvotes: 0
Views: 1660
Reputation: 6983
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',
'[email protected]',
['[email protected]', '[email protected]'],
['[email protected]'],
reply_to=['[email protected]'],
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', '[email protected]', '[email protected]'
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.
Upvotes: 1