diff options
Diffstat (limited to 'devdocs/python~3.12/library%2Femail.examples.html')
| -rw-r--r-- | devdocs/python~3.12/library%2Femail.examples.html | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/devdocs/python~3.12/library%2Femail.examples.html b/devdocs/python~3.12/library%2Femail.examples.html new file mode 100644 index 00000000..d19e8fde --- /dev/null +++ b/devdocs/python~3.12/library%2Femail.examples.html @@ -0,0 +1,353 @@ + <span id="id1"></span><h1>email: Examples</h1> <p>Here are a few examples of how to use the <a class="reference internal" href="email#module-email" title="email: Package supporting the parsing, manipulating, and generating email messages."><code>email</code></a> package to read, write, and send simple email messages, as well as more complex MIME messages.</p> <p>First, let’s see how to create and send a simple text message (both the text content and the addresses may contain unicode characters):</p> <pre data-language="python"># Import smtplib for the actual sending function +import smtplib + +# Import the email modules we'll need +from email.message import EmailMessage + +# Open the plain text file whose name is in textfile for reading. +with open(textfile) as fp: + # Create a text/plain message + msg = EmailMessage() + msg.set_content(fp.read()) + +# me == the sender's email address +# you == the recipient's email address +msg['Subject'] = f'The contents of {textfile}' +msg['From'] = me +msg['To'] = you + +# Send the message via our own SMTP server. +s = smtplib.SMTP('localhost') +s.send_message(msg) +s.quit() +</pre> <p>Parsing <span class="target" id="index-0"></span><a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc822.html"><strong>RFC 822</strong></a> headers can easily be done by the using the classes from the <a class="reference internal" href="email.parser#module-email.parser" title="email.parser: Parse flat text email messages to produce a message object structure."><code>parser</code></a> module:</p> <pre data-language="python"># Import the email modules we'll need +#from email.parser import BytesParser +from email.parser import Parser +from email.policy import default + +# If the e-mail headers are in a file, uncomment these two lines: +# with open(messagefile, 'rb') as fp: +# headers = BytesParser(policy=default).parse(fp) + +# Or for parsing headers in a string (this is an uncommon operation), use: +headers = Parser(policy=default).parsestr( + 'From: Foo Bar <user@example.com>\n' + 'To: <someone_else@example.com>\n' + 'Subject: Test message\n' + '\n' + 'Body would go here\n') + +# Now the header items can be accessed as a dictionary: +print('To: {}'.format(headers['to'])) +print('From: {}'.format(headers['from'])) +print('Subject: {}'.format(headers['subject'])) + +# You can also access the parts of the addresses: +print('Recipient username: {}'.format(headers['to'].addresses[0].username)) +print('Sender name: {}'.format(headers['from'].addresses[0].display_name)) +</pre> <p>Here’s an example of how to send a MIME message containing a bunch of family pictures that may be residing in a directory:</p> <pre data-language="python"># Import smtplib for the actual sending function. +import smtplib + +# Here are the email package modules we'll need. +from email.message import EmailMessage + +# Create the container email message. +msg = EmailMessage() +msg['Subject'] = 'Our family reunion' +# me == the sender's email address +# family = the list of all recipients' email addresses +msg['From'] = me +msg['To'] = ', '.join(family) +msg.preamble = 'You will not see this in a MIME-aware mail reader.\n' + +# Open the files in binary mode. You can also omit the subtype +# if you want MIMEImage to guess it. +for file in pngfiles: + with open(file, 'rb') as fp: + img_data = fp.read() + msg.add_attachment(img_data, maintype='image', + subtype='png') + +# Send the email via our own SMTP server. +with smtplib.SMTP('localhost') as s: + s.send_message(msg) +</pre> <p>Here’s an example of how to send the entire contents of a directory as an email message: <a class="footnote-reference brackets" href="#id3" id="id2">1</a></p> <pre data-language="python">#!/usr/bin/env python3 + +"""Send the contents of a directory as a MIME message.""" + +import os +import smtplib +# For guessing MIME type based on file name extension +import mimetypes + +from argparse import ArgumentParser + +from email.message import EmailMessage +from email.policy import SMTP + + +def main(): + parser = ArgumentParser(description="""\ +Send the contents of a directory as a MIME message. +Unless the -o option is given, the email is sent by forwarding to your local +SMTP server, which then does the normal delivery process. Your local machine +must be running an SMTP server. +""") + parser.add_argument('-d', '--directory', + help="""Mail the contents of the specified directory, + otherwise use the current directory. Only the regular + files in the directory are sent, and we don't recurse to + subdirectories.""") + parser.add_argument('-o', '--output', + metavar='FILE', + help="""Print the composed message to FILE instead of + sending the message to the SMTP server.""") + parser.add_argument('-s', '--sender', required=True, + help='The value of the From: header (required)') + parser.add_argument('-r', '--recipient', required=True, + action='append', metavar='RECIPIENT', + default=[], dest='recipients', + help='A To: header value (at least one required)') + args = parser.parse_args() + directory = args.directory + if not directory: + directory = '.' + # Create the message + msg = EmailMessage() + msg['Subject'] = f'Contents of directory {os.path.abspath(directory)}' + msg['To'] = ', '.join(args.recipients) + msg['From'] = args.sender + msg.preamble = 'You will not see this in a MIME-aware mail reader.\n' + + for filename in os.listdir(directory): + path = os.path.join(directory, filename) + if not os.path.isfile(path): + continue + # Guess the content type based on the file's extension. Encoding + # will be ignored, although we should check for simple things like + # gzip'd or compressed files. + ctype, encoding = mimetypes.guess_type(path) + if ctype is None or encoding is not None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + with open(path, 'rb') as fp: + msg.add_attachment(fp.read(), + maintype=maintype, + subtype=subtype, + filename=filename) + # Now send or store the message + if args.output: + with open(args.output, 'wb') as fp: + fp.write(msg.as_bytes(policy=SMTP)) + else: + with smtplib.SMTP('localhost') as s: + s.send_message(msg) + + +if __name__ == '__main__': + main() +</pre> <p>Here’s an example of how to unpack a MIME message like the one above, into a directory of files:</p> <pre data-language="python">#!/usr/bin/env python3 + +"""Unpack a MIME message into a directory of files.""" + +import os +import email +import mimetypes + +from email.policy import default + +from argparse import ArgumentParser + + +def main(): + parser = ArgumentParser(description="""\ +Unpack a MIME message into a directory of files. +""") + parser.add_argument('-d', '--directory', required=True, + help="""Unpack the MIME message into the named + directory, which will be created if it doesn't already + exist.""") + parser.add_argument('msgfile') + args = parser.parse_args() + + with open(args.msgfile, 'rb') as fp: + msg = email.message_from_binary_file(fp, policy=default) + + try: + os.mkdir(args.directory) + except FileExistsError: + pass + + counter = 1 + for part in msg.walk(): + # multipart/* are just containers + if part.get_content_maintype() == 'multipart': + continue + # Applications should really sanitize the given filename so that an + # email message can't be used to overwrite important files + filename = part.get_filename() + if not filename: + ext = mimetypes.guess_extension(part.get_content_type()) + if not ext: + # Use a generic bag-of-bits extension + ext = '.bin' + filename = f'part-{counter:03d}{ext}' + counter += 1 + with open(os.path.join(args.directory, filename), 'wb') as fp: + fp.write(part.get_payload(decode=True)) + + +if __name__ == '__main__': + main() +</pre> <p>Here’s an example of how to create an HTML message with an alternative plain text version. 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.</p> <pre data-language="python">#!/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 + +--Pepé +""") + +# 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("""\ +<html> + <head></head> + <body> + <p>Salut!</p> + <p>Cela ressemble à un excellent + <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718"> + recipie + </a> déjeuner. + </p> + <img src="cid:{asparagus_cid}" /> + </body> +</html> +""".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) +</pre> <p>If we were sent the message from the last example, here is one way we could process it:</p> <pre data-language="python">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 + + +def magic_html_parser(html_text, partfiles): + """Return safety-sanitized html linked to partfiles. + + Rewrite the href="cid:...." attributes to point to the filenames in partfiles. + Though not trivial, this should be possible using html.parser. + """ + raise NotImplementedError("Add the magic needed") + + +# In a real program you'd get the filename from the arguments. +with open('outgoing.msg', 'rb') as fp: + msg = BytesParser(policy=policy.default).parse(fp) + +# 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 preview 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: + 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. +</pre> <p>Up to the prompt, the output from the above is:</p> <pre data-language="none">To: Penelope Pussycat <penelope@example.com>, Fabrette Pussycat <fabrette@example.com> +From: Pepé Le Pew <pepe@example.com> +Subject: Ayons asperges pour le déjeuner + +Salut! + +Cela ressemble à un excellent recipie[1] déjeuner. +</pre> <h4 class="rubric">Footnotes</h4> <dl class="footnote brackets"> <dt class="label" id="id3"> +<code>1</code> </dt> <dd> +<p>Thanks to Matthew Dixon Cowles for the original inspiration and examples.</p> </dd> </dl> <div class="_attribution"> + <p class="_attribution-p"> + © 2001–2023 Python Software Foundation<br>Licensed under the PSF License.<br> + <a href="https://docs.python.org/3.12/library/email.examples.html" class="_attribution-link">https://docs.python.org/3.12/library/email.examples.html</a> + </p> +</div> |
