| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,56 @@ | |||
| 1 | + #!/usr/bin/env python3 | ||
| 2 | + | ||
| 3 | + import smtplib | ||
| 4 | + | ||
| 5 | + from email.message import EmailMessage | ||
| 6 | + from email.headerregistry import Address | ||
| 7 | + from email.utils import make_msgid | ||
| 8 | + | ||
| 9 | + # Create the base text message. | ||
| 10 | + msg = EmailMessage() | ||
| 11 | + msg['Subject'] = "Ayons asperges pour le déjeuner" | ||
| 12 | + msg['From'] = Address("Pepé Le Pew", "pepe@example.com") | ||
| 13 | + msg['To'] = (Address("Penelope Pussycat", "penelope@example.com"), | ||
| 14 | + Address("Fabrette Pussycat", "fabrette@example.com")) | ||
| 15 | + msg.set_content("""\ | ||
| 16 | + Salut! | ||
| 17 | + | ||
| 18 | + Cela ressemble à un excellent recipie[1] déjeuner. | ||
| 19 | + | ||
| 20 | + [1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718 | ||
| 21 | + | ||
| 22 | + --Éric | ||
| 23 | + """) | ||
| 24 | + | ||
| 25 | + # Add the html version. This converts the message into a multipart/alternative | ||
| 26 | + # container, with the original text message as the first part and the new html | ||
| 27 | + # message as the second part. | ||
| 28 | + asparagus_cid = make_msgid() | ||
| 29 | + msg.add_alternative("""\ | ||
| 30 | + <html> | ||
| 31 | + <head></head> | ||
| 32 | + <body> | ||
| 33 | + <p>Salut!<\p> | ||
| 34 | + <p>Cela ressemble à un excellent | ||
| 35 | + <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718> | ||
| 36 | + recipie | ||
| 37 | + </a> déjeuner. | ||
| 38 | + </p> | ||
| 39 | + <img src="cid:{asparagus_cid}" \> | ||
| 40 | + </body> | ||
| 41 | + </html> | ||
| 42 | + """.format(asparagus_cid=asparagus_cid[1:-1]), subtype='html') | ||
| 43 | + # note that we needed to peel the <> off the msgid for use in the html. | ||
| 44 | + | ||
| 45 | + # Now add the related image to the html part. | ||
| 46 | + with open("roasted-asparagus.jpg", 'rb') as img: | ||
| 47 | + msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg', | ||
| 48 | + cid=asparagus_cid) | ||
| 49 | + | ||
| 50 | + # Make a local copy of what we are going to send. | ||
| 51 | + with open('outgoing.msg', 'wb') as f: | ||
| 52 | + f.write(bytes(msg)) | ||
| 53 | + | ||
| 54 | + # Send the message via local SMTP server. | ||
| 55 | + with smtplib.SMTP('localhost') as s: | ||
| 56 | + s.send_message(msg) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,74 @@ | |||
| 1 | + import os | ||
| 2 | + import sys | ||
| 3 | + import tempfile | ||
| 4 | + import mimetypes | ||
| 5 | + import webbrowser | ||
| 6 | + | ||
| 7 | + # Import the email modules we'll need | ||
| 8 | + from email import policy | ||
| 9 | + from email.parser import BytesParser | ||
| 10 | + | ||
| 11 | + # An imaginary module that would make this work and be safe. | ||
| 12 | + from imaginary import magic_html_parser | ||
| 13 | + | ||
| 14 | + # In a real program you'd get the filename from the arguments. | ||
| 15 | + msg = BytesParser(policy=policy.default).parse(open('outgoing.msg', 'rb')) | ||
| 16 | + | ||
| 17 | + # Now the header items can be accessed as a dictionary, and any non-ASCII will | ||
| 18 | + # be converted to unicode: | ||
| 19 | + print('To:', msg['to']) | ||
| 20 | + print('From:', msg['from']) | ||
| 21 | + print('Subject:', msg['subject']) | ||
| 22 | + | ||
| 23 | + # If we want to print a priview of the message content, we can extract whatever | ||
| 24 | + # the least formatted payload is and print the first three lines. Of course, | ||
| 25 | + # if the message has no plain text part printing the first three lines of html | ||
| 26 | + # is probably useless, but this is just a conceptual example. | ||
| 27 | + simplest = msg.get_body(preferencelist=('plain', 'html')) | ||
| 28 | + print() | ||
| 29 | + print(''.join(simplest.get_content().splitlines(keepends=True)[:3])) | ||
| 30 | + | ||
| 31 | + ans = input("View full message?") | ||
| 32 | + if ans.lower()[0] == 'n': | ||
| 33 | + sys.exit() | ||
| 34 | + | ||
| 35 | + # We can extract the richest alternative in order to display it: | ||
| 36 | + richest = msg.get_body() | ||
| 37 | + partfiles = {} | ||
| 38 | + if richest['content-type'].maintype == 'text': | ||
| 39 | + if richest['content-type'].subtype == 'plain': | ||
| 40 | + for line in richest.get_content().splitlines(): | ||
| 41 | + print(line) | ||
| 42 | + sys.exit() | ||
| 43 | + elif richest['content-type'].subtype == 'html': | ||
| 44 | + body = richest | ||
| 45 | + else: | ||
| 46 | + print("Don't know how to display {}".format(richest.get_content_type())) | ||
| 47 | + sys.exit() | ||
| 48 | + elif richest['content-type'].content_type == 'multipart/related': | ||
| 49 | + body = richest.get_body(preferencelist=('html')) | ||
| 50 | + for part in richest.iter_attachments(): | ||
| 51 | + fn = part.get_filename() | ||
| 52 | + if fn: | ||
| 53 | + extension = os.path.splitext(part.get_filename())[1] | ||
| 54 | + else: | ||
| 55 | + extension = mimetypes.guess_extension(part.get_content_type()) | ||
| 56 | + with tempfile.NamedTemporaryFile(suffix=extension, delete=False) as f: | ||
| 57 | + f.write(part.get_content()) | ||
| 58 | + # again strip the <> to go from email form of cid to html form. | ||
| 59 | + partfiles[part['content-id'][1:-1]] = f.name | ||
| 60 | + else: | ||
| 61 | + print("Don't know how to display {}".format(richest.get_content_type())) | ||
| 62 | + sys.exit() | ||
| 63 | + with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: | ||
| 64 | + # The magic_html_parser has to rewrite the href="cid:...." attributes to | ||
| 65 | + # point to the filenames in partfiles. It also has to do a safety-sanitize | ||
| 66 | + # of the html. It could be written using html.parser. | ||
| 67 | + f.write(magic_html_parser(body.get_content(), partfiles)) | ||
| 68 | + webbrowser.open(f.name) | ||
| 69 | + os.remove(f.name) | ||
| 70 | + for fn in partfiles.values(): | ||
| 71 | + os.remove(fn) | ||
| 72 | + | ||
| 73 | + # Of course, there are lots of email messages that could break this simple | ||
| 74 | + # minded program, but it will handle the most common ones. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -40,6 +40,34 @@ text version: [2]_ | |||
| 40 | 40 | .. literalinclude:: ../includes/email-alternative.py | |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | + Examples using the Provision API | ||
| 44 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 45 | + Here is a reworking of the last example using the provisional API. To make | ||
| 46 | + things a bit more interesting, we include a related image in the html part, and | ||
| 47 | + we save a copy of what we are going to send to disk, as well as sending it. | ||
| 48 | + | ||
| 49 | + This example also shows how easy it is to include non-ASCII, and simplifies the | ||
| 50 | + sending of the message using the :meth:`.send_message` method of the | ||
| 51 | + :mod:`smtplib` module. | ||
| 52 | + | ||
| 53 | + .. literalinclude:: ../includes/email-alternative-new-api.py | ||
| 54 | + | ||
| 55 | + If we were instead sent the message from the last example, here is one | ||
| 56 | + way we could process it: | ||
| 57 | + | ||
| 58 | + .. literalinclude:: ../includes/email-read-alternative-new-api.py | ||
| 59 | + | ||
| 60 | + Up to the prompt, the output from the above is:: | ||
| 61 | + | ||
| 62 | + To: Penelope Pussycat <"penelope@example.com">, Fabrette Pussycat <"fabrette@example.com"> | ||
| 63 | + From: Pepé Le Pew <pepe@example.com> | ||
| 64 | + Subject: Ayons asperges pour le déjeuner | ||
| 65 | + | ||
| 66 | + Salut! | ||
| 67 | + | ||
| 68 | + Cela ressemble à un excellent recipie[1] déjeuner. | ||
| 69 | + | ||
| 70 | + | ||
| 43 | 71 | .. rubric:: Footnotes | |
| 44 | 72 | ||
| 45 | 73 | .. [1] Thanks to Matthew Dixon Cowles for the original inspiration and examples. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments