[Python-Dev] Completing the email6 API changes.

Stephen J. Turnbull stephen at xemacs.org
Sat Aug 31 11:57:56 CEST 2013

R. David Murray writes:

 > But I would certainly appreciate review from anyone so moved, since I
 > haven't gotten any yet.

I'll try to make time for a serious (but obviously partial) review by

I don't know if this is "serious" bikeshedding, but I have a comment
or two on the example:

 >     from email.message import MIMEMessage
 >     from email.headerregistry import Address
 >     fullmsg = MIMEMessage()
 >     fullmsg['To'] = Address('Foö Bar', 'fbar at example.com')
 >     fullmsg['From'] = "mè <me at example.com>"
 >     fullmsg['Subject'] = "j'ai un problème de python."

This is very nice!  *I* *love* it.

But (sorry!) I worry that it's not obvious to "naive" users.  Maybe it
would be useful to have a Message() factory which has one semantic
difference from MIMEMessage: it "requires" RFC 822-required headers
(or optionally RFC 1036 for news).  Eg:

    # This message will be posted and mailed
    # These would conform to the latest Draft Standards
    # and be DKIM-signed
    fullmsg = Message('rfc822', 'rfc1036', 'dmarc')

I'm not sure how "required" would be implemented (perhaps through a
.validate() method).  So the signature of the API suggested above is
Message(*validators, **kw).

For MIMEMessage, I think I prefer the name "MIMEPart".  To naive
users, the idea of MIMEMessages containing MIMEMessages is a bit
disconcerting, except in the case of multipart/digest, I think.

 >     fullmsg.set_content("et la il est monté sur moi et il commence"
 >                        " a m'étouffer.")
 >     htmlmsg = MIMEMessage()
 >     htmlmsg.set_content("<p>et la il est monté sur moi et il commence"
 >                         " a m'étouffer.</p><img src='image1' />",
 >                         subtype='html')

I think I'd like to express the suite above as

    fullmsg.payload.add_alternative(..., subtype='html')

This would automatically convert the MIME type of fullmsg to
'multipart/alternative', and .payload to a list where necessary.
.set_content() would be available but it's "dangerous" (it could
replace an arbitrary multipart -- this would be useful operation to
replace it with a textual URL or external-body part).

Aside: it occurs to me that the .payload attribute (and other such
attributes) could be avoided by the device of using names prefixed by
":" such as ":payload" as keys: "fullmsg[':payload']" since colon is
illegal in field names (cf RFC 5322).  Probably I've just been writing
too much Common Lisp, though.<wink/>

I'm not sure whether "payload" is a better name than "content" for
that attribute.

Now the suite

 >     with open('python.jpg', 'rb') as python:
 >         htmlmsg.add_related(python.read(), 'image', 'jpg', cid='image1'
 >                             disposition='inline')
 >     fullmsg.make_alternative()
 >     fullmsg.attach(htmlmsg)

becomes just

    with open('python.jpg', 'rb') as python:

At this point, "fullmsg.add_related()" without the .payload attribute
would be an error, unless a "insertPart=True" keyword argument were
present.  With "insertPart=True", a new top-level multipart/related
would be interposed with the existing multipart/alternative as its
first child, and the argument of add_related as the second.  Maybe
that's too complicated, but I suspect it's harder for people who think
of MIME messages as trees, than for people who think of messages as
documents and don't want to hear about mimes other than Marcel

The indexing of the .payload attribute by part type is perhaps too
smart for my own good, haven't thought carefully about it.  It's
plausible, though, since a message with multiple parts of the same
type can only have one displayed -- normally that shouldn't happen.
OTOH, this wouldn't work without modification for multipart/mixed or
multipart/related.  Could use Yet Another Keyword Argument, maybe.

(BTW, it's really annoying when the text/plain part refers to images
etc that are attached only to the text/html part.  AFAICT from RFC
2387 it ought to be possible to put the multipart/related part at the
top so both text/html and text/plain can refer to it.)

 >     with open('police-report.txt') as report:
 >         fullmsg.add_attachment(report.read(), filename='pölice-report.txt',
 >                                params=dict(wrap='flow'), headers=(
 >                                     'X-Secret-Level: top',
 >                                     'X-Authorization: Monty'))

I can't find an RFC that specifies a "wrap" parameter to text/plain.
Do you mean RFC 2646 'format="flowed"' here?

(A "validate" method could raise a warning on unregistered parameters.)

 > (Hmm.  Looking at that I see I didn't fully fix a bug I had meant to fix:
 > some of the parts have a MIME-Version header that don't need it.)

Another reason why the top-level part should be treated differently in
the API.


More information about the Python-Dev mailing list