email示例

以下是一些如何使用email包来读取,写入和发送简单电子邮件以及更复杂的MIME消息的示例.

首先,让我们看看如何创建和发送简单的文本消息(文本内容和地址都可能包含unicode字符):

# Import smtplib for the actual sending functionimport smtplib# Import the email modules we"ll needfrom 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 addressmsg["Subject"] = "The contents of %s" % textfilemsg["From"] = memsg["To"] = you# Send the message via our own SMTP server.s = smtplib.SMTP("localhost")s.send_message(msg)s.quit()

解析 RFC 822 标题很容易通过使用parser模块中的类来完成:

# Import the email modules we"ll needfrom email.parser import BytesParser, Parserfrom 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 <[email protected]>\n"        "To: <[email protected]>\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))

这是一个如何发送包含可能驻留在目录中的一系列家庭图片的MIME消息的示例

# Import smtplib for the actual sending functionimport smtplib# And imghdr to find the types of our imagesimport imghdr# Here are the email package modules we"ll needfrom 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 addressesmsg["From"] = memsg["To"] = ", ".join(family)msg.preamble = "Our family reunion"# Open the files in binary mode.  Use imghdr to figure out the# MIME subtype for each specific image.for file in pngfiles:    with open(file, "rb") as fp:        img_data = fp.read()    msg.add_attachment(img_data, maintype="image",                                 subtype=imghdr.what(None, img_data))# Send the email via our own SMTP server.with smtplib.SMTP("localhost") as s:    s.send_message(msg)

这是一个如何将目录的全部内容作为电子邮件消息发送的示例:[1]

#!/usr/bin/env python3"""Send the contents of a directory as a MIME message."""import osimport smtplib# For guessing MIME type based on file name extensionimport mimetypesfrom argparse import ArgumentParserfrom email.message import EmailMessagefrom email.policy import SMTPdef 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 localSMTP server, which then does the normal delivery process.  Your local machinemust 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"] = "Contents of directory %s" % 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()

以下是如何将MIME消息(如上所述)解压缩到文件目录中的示例

#!/usr/bin/env python3"""Unpack a MIME message into a directory of files."""import osimport emailimport mimetypesfrom email.policy import defaultfrom argparse import ArgumentParserdef 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 = "part-%03d%s" % (counter, 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()

这是一个如何使用替代纯文本版本创建HTML消息的示例。为了让事情变得更有趣,我们在html部分中包含了一个相关图像,我们保存了我们要发送的东西的副本,以及发送它.

#!/usr/bin/env python3import smtplibfrom email.message import EmailMessagefrom email.headerregistry import Addressfrom 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)

如果我们从最后一个例子中发送了消息,这是我们处理它的一种方式:

import osimport sysimport tempfileimport mimetypesimport webbrowser# Import the email modules we"ll needfrom email import policyfrom 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.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.nameelse:    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.

到提示符,上面的输出是:

To: Penelope Pussycat <[email protected]>, Fabrette Pussycat <[email protected]>From: Pepé Le Pew <[email protected]>Subject: Ayons asperges pour le déjeunerSalut!Cela ressemble à un excellent recipie[1] déjeuner.

脚注

[1] 感谢Matthew Dixon Cowles的原创灵感和实例.

评论被关闭。