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 Monday.
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', 'email@example.com') fullmsg['From'] = "mÃ¨ <firstname.lastname@example.org>" 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(...) 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)
with open('python.jpg', 'rb') as python: fullmsg.payload['text/html'].add_related(...)
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 Marceau.<wink/>
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.