#24277: The new email API is no longer provisional.
This is a wholesale reorganization and editing of the email documentation to
make the new API the standard one, and the old API the 'legacy' one. The
default is still the compat32 policy, for backward compatibility. We will
change that eventually.
diff --git a/Doc/includes/email-alternative-new-api.py b/Doc/includes/email-alternative-new-api.py
deleted file mode 100644
index 321f727..0000000
--- a/Doc/includes/email-alternative-new-api.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/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)
diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py
old mode 100755
new mode 100644
index 85070f3..321f727
--- a/Doc/includes/email-alternative.py
+++ b/Doc/includes/email-alternative.py
@@ -2,47 +2,55 @@
import smtplib
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
+from email.message import EmailMessage
+from email.headerregistry import Address
+from email.utils import make_msgid
-# me == my email address
-# you == recipient's email address
-me = "my@email.com"
-you = "your@email.com"
+# 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!
-# Create message container - the correct MIME type is multipart/alternative.
-msg = MIMEMultipart('alternative')
-msg['Subject'] = "Link"
-msg['From'] = me
-msg['To'] = you
+Cela ressemble à un excellent recipie[1] déjeuner.
-# Create the body of the message (a plain-text and an HTML version).
-text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org"
-html = """\
+[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>Hi!<br>
- How are you?<br>
- Here is the <a href="https://www.python.org">link</a> you wanted.
+ <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.
-# Record the MIME types of both parts - text/plain and text/html.
-part1 = MIMEText(text, 'plain')
-part2 = MIMEText(html, '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)
-# Attach parts into message container.
-# According to RFC 2046, the last part of a multipart message, in this case
-# the HTML message, is best and preferred.
-msg.attach(part1)
-msg.attach(part2)
+# 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.
-s = smtplib.SMTP('localhost')
-# sendmail function takes 3 arguments: sender's address, recipient's address
-# and message to send - here it is sent as one string.
-s.sendmail(me, you, msg.as_string())
-s.quit()
+with smtplib.SMTP('localhost') as s:
+ s.send_message(msg)
diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py
index 3c7c770..0dcfbfb 100644
--- a/Doc/includes/email-dir.py
+++ b/Doc/includes/email-dir.py
@@ -3,22 +3,14 @@
"""Send the contents of a directory as a MIME message."""
import os
-import sys
import smtplib
# For guessing MIME type based on file name extension
import mimetypes
from argparse import ArgumentParser
-from email import encoders
-from email.message import Message
-from email.mime.audio import MIMEAudio
-from email.mime.base import MIMEBase
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
-COMMASPACE = ', '
+from email.message import EmailMessage
+from email.policy import SMTP
def main():
@@ -47,12 +39,12 @@
directory = args.directory
if not directory:
directory = '.'
- # Create the enclosing (outer) message
- outer = MIMEMultipart()
- outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory)
- outer['To'] = COMMASPACE.join(args.recipients)
- outer['From'] = args.sender
- outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'
+ # 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)
@@ -67,33 +59,18 @@
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
- if maintype == 'text':
- with open(path) as fp:
- # Note: we should handle calculating the charset
- msg = MIMEText(fp.read(), _subtype=subtype)
- elif maintype == 'image':
- with open(path, 'rb') as fp:
- msg = MIMEImage(fp.read(), _subtype=subtype)
- elif maintype == 'audio':
- with open(path, 'rb') as fp:
- msg = MIMEAudio(fp.read(), _subtype=subtype)
- else:
- with open(path, 'rb') as fp:
- msg = MIMEBase(maintype, subtype)
- msg.set_payload(fp.read())
- # Encode the payload using Base64
- encoders.encode_base64(msg)
- # Set the filename parameter
- msg.add_header('Content-Disposition', 'attachment', filename=filename)
- outer.attach(msg)
+ with open(path, 'rb') as fp:
+ msg.add_attachment(fp.read(),
+ maintype=maintype,
+ subtype=subtype,
+ filename=filename)
# Now send or store the message
- composed = outer.as_string()
if args.output:
- with open(args.output, 'w') as fp:
- fp.write(composed)
+ with open(args.output, 'wb') as fp:
+ fp.write(msg.as_bytes(policy=SMTP))
else:
with smtplib.SMTP('localhost') as s:
- s.sendmail(args.sender, args.recipients, composed)
+ s.send_message(msg)
if __name__ == '__main__':
diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py
index 89c8f3a..2c42145 100644
--- a/Doc/includes/email-headers.py
+++ b/Doc/includes/email-headers.py
@@ -1,18 +1,24 @@
# Import the email modules we'll need
-from email.parser import Parser
+from email.parser import BytesParser, Parser
+from email.policy import default
# If the e-mail headers are in a file, uncomment these two lines:
-# with open(messagefile) as fp:
-# headers = Parser().parse(fp)
+# with open(messagefile, 'rb') as fp:
+# headers = BytesParser(policy=default).parse(fp)
-# Or for parsing headers in a string, use:
-headers = Parser().parsestr('From: <user@example.com>\n'
+# 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: %s' % headers['to'])
-print('From: %s' % headers['from'])
-print('Subject: %s' % headers['subject'])
+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))
diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py
index 61d0830..c610242 100644
--- a/Doc/includes/email-mime.py
+++ b/Doc/includes/email-mime.py
@@ -1,30 +1,29 @@
# Import smtplib for the actual sending function
import smtplib
+# And imghdr to find the types of our images
+import imghdr
+
# Here are the email package modules we'll need
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
+from email.message import EmailMessage
-COMMASPACE = ', '
-
-# Create the container (outer) email message.
-msg = MIMEMultipart()
+# 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'] = COMMASPACE.join(family)
+msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
-# Assume we know that the image files are all in PNG format
+# Open the files in binary mode. Use imghdr to figure out the
+# MIME subtype for each specific image.
for file in pngfiles:
- # Open the files in binary mode. Let the MIMEImage class automatically
- # guess the specific image type.
with open(file, 'rb') as fp:
- img = MIMEImage(fp.read())
- msg.attach(img)
+ 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.
-s = smtplib.SMTP('localhost')
-s.send_message(msg)
-s.quit()
+with smtplib.SMTP('localhost') as s:
+ s.send_message(msg)
diff --git a/Doc/includes/email-read-alternative-new-api.py b/Doc/includes/email-read-alternative.py
similarity index 100%
rename from Doc/includes/email-read-alternative-new-api.py
rename to Doc/includes/email-read-alternative.py
diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py
index b9b8b41..f69ef40 100644
--- a/Doc/includes/email-simple.py
+++ b/Doc/includes/email-simple.py
@@ -2,13 +2,13 @@
import smtplib
# Import the email modules we'll need
-from email.mime.text import MIMEText
+from email.message import EmailMessage
-# Open a plain text file for reading. For this example, assume that
-# the text file contains only ASCII characters.
+# Open the plain text file whose name is in textfile for reading.
with open(textfile) as fp:
# Create a text/plain message
- msg = MIMEText(fp.read())
+ msg = EmailMessage()
+ msg.set_content(fp.read())
# me == the sender's email address
# you == the recipient's email address
diff --git a/Doc/includes/email-unpack.py b/Doc/includes/email-unpack.py
index 574a0b6..e0a7f01 100644
--- a/Doc/includes/email-unpack.py
+++ b/Doc/includes/email-unpack.py
@@ -3,11 +3,11 @@
"""Unpack a MIME message into a directory of files."""
import os
-import sys
import email
-import errno
import mimetypes
+from email.policy import default
+
from argparse import ArgumentParser
@@ -22,8 +22,8 @@
parser.add_argument('msgfile')
args = parser.parse_args()
- with open(args.msgfile) as fp:
- msg = email.message_from_file(fp)
+ with open(args.msgfile, 'rb') as fp:
+ msg = email.message_from_binary_file(fp, policy=default)
try:
os.mkdir(args.directory)