diff -r b3f034f5000f Doc/includes/email-alternative-new-api.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doc/includes/email-alternative-new-api.py Sat Feb 01 17:43:51 2014 -0500 @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +import smtplib + +from email.message import EmailMessage +from email.headerregistry import Address +from email.utils import make_msgid + +# Create the base text message. +msg = EmailMessage() +msg['Subject'] = "Ayons asperges pour le déjeuner" +msg['From'] = Address("Pepé Le Pew", "pepe@example.com") +msg['To'] = (Address("Penelope Pussycat", "penelope@example.com"), + Address("Fabrette Pussycat", "fabrette@example.com")) +msg.set_content("""\ +Salut! + +Cela ressemble à un excellent recipie[1] déjeuner. + +[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718 + +--Éric +""") + +# Add the html version. This converts the message into a multipart/alternative +# container, with the original text message as the first part and the new html +# message as the second part. +asparagus_cid = make_msgid() +msg.add_alternative("""\ + + + +

Salut!<\p> +

Cela ressemble à un excellent + + + +""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html') +# note that we needed to peel the <> off the msgid for use in the html. + +# Now add the related image to the html part. +with open("roasted-asparagus.jpg", 'rb') as img: + msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg', + cid=asparagus_cid) + +# Make a local copy of what we are going to send. +with open('outgoing.msg', 'wb') as f: + f.write(bytes(msg)) + +# Send the message via local SMTP server. +with smtplib.SMTP('localhost') as s: + s.send_message(msg) diff -r b3f034f5000f Doc/includes/email-read-alternative-new-api.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doc/includes/email-read-alternative-new-api.py Sat Feb 01 17:43:51 2014 -0500 @@ -0,0 +1,74 @@ +import os +import sys +import tempfile +import mimetypes +import webbrowser + +# Import the email modules we'll need +from email import policy +from email.parser import BytesParser + +# An imaginary module that would make this work and be safe. +from imaginary import magic_html_parser + +# In a real program you'd get the filename from the arguments. +msg = BytesParser(policy=policy.default).parse(open('outgoing.msg', 'rb')) + +# Now the header items can be accessed as a dictionary, and any non-ASCII will +# be converted to unicode: +print('To:', msg['to']) +print('From:', msg['from']) +print('Subject:', msg['subject']) + +# If we want to print a priview of the message content, we can extract whatever +# the least formatted payload is and print the first three lines. Of course, +# if the message has no plain text part printing the first three lines of html +# is probably useless, but this is just a conceptual example. +simplest = msg.get_body(preferencelist=('plain', 'html')) +print() +print(''.join(simplest.get_content().splitlines(keepends=True)[:3])) + +ans = input("View full message?") +if ans.lower()[0] == 'n': + sys.exit() + +# We can extract the richest alternative in order to display it: +richest = msg.get_body() +partfiles = {} +if richest['content-type'].maintype == 'text': + if richest['content-type'].subtype == 'plain': + for line in richest.get_content().splitlines(): + print(line) + sys.exit() + elif richest['content-type'].subtype == 'html': + body = richest + else: + print("Don't know how to display {}".format(richest.get_content_type())) + sys.exit() +elif richest['content-type'].content_type == 'multipart/related': + body = richest.get_body(preferencelist=('html')) + for part in richest.iter_attachments(): + fn = part.get_filename() + if fn: + extension = os.path.splitext(part.get_filename())[1] + else: + extension = mimetypes.guess_extension(part.get_content_type()) + with tempfile.NamedTemporaryFile(suffix=extension, delete=False) as f: + f.write(part.get_content()) + # again strip the <> to go from email form of cid to html form. + partfiles[part['content-id'][1:-1]] = f.name +else: + print("Don't know how to display {}".format(richest.get_content_type())) + sys.exit() +with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: + # The magic_html_parser has to rewrite the href="cid:...." attributes to + # point to the filenames in partfiles. It also has to do a safety-sanitize + # of the html. It could be written using html.parser. + f.write(magic_html_parser(body.get_content(), partfiles)) +webbrowser.open(f.name) +os.remove(f.name) +for fn in partfiles.values(): + os.remove(fn) + +# Of course, there are lots of email messages that could break this simple +# minded program, but it will handle the most common ones. diff -r b3f034f5000f Doc/library/email-examples.rst --- a/Doc/library/email-examples.rst Sat Feb 01 12:27:07 2014 -0500 +++ b/Doc/library/email-examples.rst Sat Feb 01 17:43:51 2014 -0500 @@ -40,6 +40,34 @@ .. literalinclude:: ../includes/email-alternative.py +Examples using the Provision API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Here is a reworking of the last example using the provisional API. To make +things a bit more interesting, we include a related image in the html part, and +we save a copy of what we are going to send to disk, as well as sending it. + +This example also shows how easy it is to include non-ASCII, and simplifies the +sending of the message using the :meth:`.send_message` method of the +:mod:`smtplib` module. + +.. literalinclude:: ../includes/email-alternative-new-api.py + +If we were instead sent the message from the last example, here is one +way we could process it: + +.. literalinclude:: ../includes/email-read-alternative-new-api.py + +Up to the prompt, the output from the above is:: + + To: Penelope Pussycat <"penelope@example.com">, Fabrette Pussycat <"fabrette@example.com"> + From: Pepé Le Pew + Subject: Ayons asperges pour le déjeuner + + Salut! + + Cela ressemble à un excellent recipie[1] déjeuner. + + .. rubric:: Footnotes .. [1] Thanks to Matthew Dixon Cowles for the original inspiration and examples.