For a slightly more clarified and distilled version of these thoughts, please see
TaoOfEmail.
- MIME-ness in Chandler should encapsulate the ability to convert an item to a format suitable for transport via SMTP/MIME.
- Any MIME object should be able to return two things:
- A dictionary of headers
- A body attribute
- Both might be calculated.
- In Chandler, they should also provide a function to convert themselves to either a flat string representation or an email.Message.Message object (we'll call this MailStamp.toEmailMessage).
- MailStamp objects might have some extra stuff, but if we want any MailStamp'd object to be transported by SMTP+MIME, it should still have the two things required by a MIME object.
MailStamp objects could be the only MIME-y object in the Chandler, so long as the body attribute were calculated differently for multipart MailStamps and non-multipart MailStamps. This could be built into MailStamp.toEmailMessage.
One problem with this is the fact that it would make all subparts of a multipart message look like full fledged MailStamp items. One way to fix this would be to provide a new class, MIMEPart, and make MailStamp a subclass of it. This is very similar to the way Twisted's imap code handles MIME.
The following is a first pass at a schema for MailStamp. It should probably be refined to make sure it matches the appropriate MIME RFCs.
The body and headers attributes are calculated in slightly different ways. We could:
- Calculate them both the way headers are currently calculated
- Calculate them both the way the body is currently calculated
- Do them in different ways similar to the way it is now
I'm not sure which of these is best.
I'm not entirely happy with this, but that's why it's a first pass
from osaf.pim.calculated import Calculated
class MIMEPart(Annotation): # there might be a better name for this
schema.kindInfo(annotates=ContentItem)
headers = schema.Mapping(schema.Text, initialValue = {})
body = Calculated(schema.Text,
basedOn = ('mimeParts'),
fget=_get_body_string)
text_body = schema.One(schema.Text,
doc = "A string representation of the body of "
"this part. Overridden if self.isMultipart == True"
)
mimeParts = schema.Sequence(MIMEPart, initialValue = [])
< other attributes like subject, from, etc could be pointers into the headers dict >
< OR the headers attribute could be calculated from these attributes >
def _get_body_string(self):
if self.isMultipart():
boundary = #<... calculate boundary string and set appropriate header ...>
return boundary.join([MIMEPart(part).body for part in self.mimeParts])
else:
return getattr(self, "text_body", self.itsItem.body)
def isMultipart(self):
return len(self.mimeParts) > 0:
def toMessageObject(self):
header_dict = getattr(self, "mimeHeaders", {}).copy()
header_dict.update(self.headers)
#< construct email.Message.Message object... >
return #<email.Message.Message object>
def toMessageString(self):
# This would be a convenience method to avoid creating
# an email.Message.Message object.
# It could be kept or not.
class MailStamp(MIMEPart):
# Not sure what to put here.
# It might be useful just to mark the toplevel-ness of an individual mail message.
pass
One major problem that still remains is handling VERY LARGE attachments. Currently, this will mean tons of memory and slow object creation.
This could be an acute problem if we support the toMessageObject method, which could cause a complete duplication of the message.
--
TravisVachon - 30 Aug 2006