Merge email package 4.0 from the sandbox, including documentation, test cases,
and NEWS updates.
This commit is contained in:
parent
9ae019bf5b
commit
40ef0067ad
|
@ -1,83 +1,69 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""Send the contents of a directory as a MIME message.
|
||||
"""Send the contents of a directory as a MIME message."""
|
||||
|
||||
Usage: dirmail [options] from to [to ...]*
|
||||
|
||||
Options:
|
||||
-h / --help
|
||||
Print this message and exit.
|
||||
|
||||
-d directory
|
||||
--directory=directory
|
||||
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.
|
||||
|
||||
`from' is the email address of the sender of the message.
|
||||
|
||||
`to' is the email address of the recipient of the message, and multiple
|
||||
recipients may be 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.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import sys
|
||||
import smtplib
|
||||
# For guessing MIME type based on file name extension
|
||||
import mimetypes
|
||||
|
||||
from email import Encoders
|
||||
from email.Message import Message
|
||||
from email.MIMEAudio import MIMEAudio
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEImage import MIMEImage
|
||||
from email.MIMEText import MIMEText
|
||||
from optparse import OptionParser
|
||||
|
||||
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 = ', '
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print >> sys.stderr, __doc__
|
||||
if msg:
|
||||
print >> sys.stderr, msg
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'hd:', ['help', 'directory='])
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
parser = OptionParser(usage="""\
|
||||
Send the contents of a directory as a MIME message.
|
||||
|
||||
dir = os.curdir
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-d', '--directory'):
|
||||
dir = arg
|
||||
|
||||
if len(args) < 2:
|
||||
usage(1)
|
||||
|
||||
sender = args[0]
|
||||
recips = args[1:]
|
||||
Usage: %prog [options]
|
||||
|
||||
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_option('-d', '--directory',
|
||||
type='string', action='store',
|
||||
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_option('-o', '--output',
|
||||
type='string', action='store', metavar='FILE',
|
||||
help="""Print the composed message to FILE instead of
|
||||
sending the message to the SMTP server.""")
|
||||
parser.add_option('-s', '--sender',
|
||||
type='string', action='store', metavar='SENDER',
|
||||
help='The value of the From: header (required)')
|
||||
parser.add_option('-r', '--recipient',
|
||||
type='string', action='append', metavar='RECIPIENT',
|
||||
default=[], dest='recipients',
|
||||
help='A To: header value (at least one required)')
|
||||
opts, args = parser.parse_args()
|
||||
if not opts.sender or not opts.recipients:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
directory = opts.directory
|
||||
if not directory:
|
||||
directory = '.'
|
||||
# Create the enclosing (outer) message
|
||||
outer = MIMEMultipart()
|
||||
outer['Subject'] = 'Contents of directory %s' % os.path.abspath(dir)
|
||||
outer['To'] = COMMASPACE.join(recips)
|
||||
outer['From'] = sender
|
||||
outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory)
|
||||
outer['To'] = COMMASPACE.join(opts.recipients)
|
||||
outer['From'] = opts.sender
|
||||
outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'
|
||||
# To guarantee the message ends with a newline
|
||||
outer.epilogue = ''
|
||||
|
||||
for filename in os.listdir(dir):
|
||||
path = os.path.join(dir, filename)
|
||||
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
|
||||
|
@ -108,16 +94,21 @@ def main():
|
|||
msg.set_payload(fp.read())
|
||||
fp.close()
|
||||
# Encode the payload using Base64
|
||||
Encoders.encode_base64(msg)
|
||||
encoders.encode_base64(msg)
|
||||
# Set the filename parameter
|
||||
msg.add_header('Content-Disposition', 'attachment', filename=filename)
|
||||
outer.attach(msg)
|
||||
|
||||
# Now send the message
|
||||
s = smtplib.SMTP()
|
||||
s.connect()
|
||||
s.sendmail(sender, recips, outer.as_string())
|
||||
s.close()
|
||||
# Now send or store the message
|
||||
composed = outer.as_string()
|
||||
if opts.output:
|
||||
fp = open(opts.output, 'w')
|
||||
fp.write(composed)
|
||||
fp.close()
|
||||
else:
|
||||
s = smtplib.SMTP()
|
||||
s.connect()
|
||||
s.sendmail(opts.sender, opts.recipients, composed)
|
||||
s.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import smtplib
|
||||
|
||||
# Here are the email package modules we'll need
|
||||
from email.MIMEImage import MIMEImage
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.mime.image import MIMEImage
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
COMMASPACE = ', '
|
||||
|
||||
|
@ -15,8 +15,6 @@ msg['Subject'] = 'Our family reunion'
|
|||
msg['From'] = me
|
||||
msg['To'] = COMMASPACE.join(family)
|
||||
msg.preamble = 'Our family reunion'
|
||||
# Guarantees the message ends in a newline
|
||||
msg.epilogue = ''
|
||||
|
||||
# Assume we know that the image files are all in PNG format
|
||||
for file in pngfiles:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import smtplib
|
||||
|
||||
# Import the email modules we'll need
|
||||
from email.MIMEText import MIMEText
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
# Open a plain text file for reading. For this example, assume that
|
||||
# the text file contains only ASCII characters.
|
||||
|
|
|
@ -1,59 +1,44 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""Unpack a MIME message into a directory of files.
|
||||
"""Unpack a MIME message into a directory of files."""
|
||||
|
||||
Usage: unpackmail [options] msgfile
|
||||
|
||||
Options:
|
||||
-h / --help
|
||||
Print this message and exit.
|
||||
|
||||
-d directory
|
||||
--directory=directory
|
||||
Unpack the MIME message into the named directory, which will be
|
||||
created if it doesn't already exist.
|
||||
|
||||
msgfile is the path to the file containing the MIME message.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import sys
|
||||
import email
|
||||
import errno
|
||||
import mimetypes
|
||||
import email
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print >> sys.stderr, __doc__
|
||||
if msg:
|
||||
print >> sys.stderr, msg
|
||||
sys.exit(code)
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'hd:', ['help', 'directory='])
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
parser = OptionParser(usage="""\
|
||||
Unpack a MIME message into a directory of files.
|
||||
|
||||
dir = os.curdir
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-d', '--directory'):
|
||||
dir = arg
|
||||
Usage: %prog [options] msgfile
|
||||
""")
|
||||
parser.add_option('-d', '--directory',
|
||||
type='string', action='store',
|
||||
help="""Unpack the MIME message into the named
|
||||
directory, which will be created if it doesn't already
|
||||
exist.""")
|
||||
opts, args = parser.parse_args()
|
||||
if not opts.directory:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
msgfile = args[0]
|
||||
except IndexError:
|
||||
usage(1)
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
os.mkdir(dir)
|
||||
os.mkdir(opts.directory)
|
||||
except OSError, e:
|
||||
# Ignore directory exists error
|
||||
if e.errno <> errno.EEXIST: raise
|
||||
if e.errno <> errno.EEXIST:
|
||||
raise
|
||||
|
||||
fp = open(msgfile)
|
||||
msg = email.message_from_file(fp)
|
||||
|
@ -74,8 +59,8 @@ def main():
|
|||
ext = '.bin'
|
||||
filename = 'part-%03d%s' % (counter, ext)
|
||||
counter += 1
|
||||
fp = open(os.path.join(dir, filename), 'wb')
|
||||
fp.write(part.get_payload(decode=1))
|
||||
fp = open(os.path.join(opts.directory, filename), 'wb')
|
||||
fp.write(part.get_payload(decode=True))
|
||||
fp.close()
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
% Copyright (C) 2001-2004 Python Software Foundation
|
||||
% Copyright (C) 2001-2006 Python Software Foundation
|
||||
% Author: barry@python.org (Barry Warsaw)
|
||||
|
||||
\section{\module{email} ---
|
||||
|
@ -18,10 +18,10 @@ subsumes most of the functionality in several older standard modules
|
|||
such as \refmodule{rfc822}, \refmodule{mimetools},
|
||||
\refmodule{multifile}, and other non-standard packages such as
|
||||
\module{mimecntl}. It is specifically \emph{not} designed to do any
|
||||
sending of email messages to SMTP (\rfc{2821}) servers; that is the
|
||||
function of the \refmodule{smtplib} module. The \module{email}
|
||||
package attempts to be as RFC-compliant as possible, supporting in
|
||||
addition to \rfc{2822}, such MIME-related RFCs as
|
||||
sending of email messages to SMTP (\rfc{2821}), NNTP, or other servers; those
|
||||
are functions of modules such as \refmodule{smtplib} and \refmodule{nntplib}.
|
||||
The \module{email} package attempts to be as RFC-compliant as possible,
|
||||
supporting in addition to \rfc{2822}, such MIME-related RFCs as
|
||||
\rfc{2045}, \rfc{2046}, \rfc{2047}, and \rfc{2231}.
|
||||
|
||||
The primary distinguishing feature of the \module{email} package is
|
||||
|
@ -41,7 +41,7 @@ The following sections describe the functionality of the
|
|||
should be common in applications: an email message is read as flat
|
||||
text from a file or other source, the text is parsed to produce the
|
||||
object structure of the email message, this structure is manipulated,
|
||||
and finally rendered back into flat text.
|
||||
and finally, the object tree is rendered back into flat text.
|
||||
|
||||
It is perfectly feasible to create the object structure out of whole
|
||||
cloth --- i.e. completely from scratch. From there, a similar
|
||||
|
@ -56,6 +56,7 @@ package, a section on differences and porting is provided.
|
|||
|
||||
\begin{seealso}
|
||||
\seemodule{smtplib}{SMTP protocol client}
|
||||
\seemodule{nntplib}{NNTP protocol client}
|
||||
\end{seealso}
|
||||
|
||||
\subsection{Representing an email message}
|
||||
|
@ -88,22 +89,51 @@ package, a section on differences and porting is provided.
|
|||
\subsection{Iterators}
|
||||
\input{emailiter}
|
||||
|
||||
\subsection{Package History}
|
||||
\subsection{Package History\label{email-pkg-history}}
|
||||
|
||||
Version 1 of the \module{email} package was bundled with Python
|
||||
releases up to Python 2.2.1. Version 2 was developed for the Python
|
||||
2.3 release, and backported to Python 2.2.2. It was also available as
|
||||
a separate distutils-based package, and is compatible back to Python 2.1.
|
||||
This table describes the release history of the email package, corresponding
|
||||
to the version of Python that the package was released with. For purposes of
|
||||
this document, when you see a note about change or added versions, these refer
|
||||
to the Python version the change was made it, \emph{not} the email package
|
||||
version. This table also describes the Python compatibility of each version
|
||||
of the package.
|
||||
|
||||
\module{email} version 3.0 was released with Python 2.4 and as a separate
|
||||
distutils-based package. It is compatible back to Python 2.3.
|
||||
\begin{tableiii}{l|l|l}{constant}{email version}{distributed with}{compatible with}
|
||||
\lineiii{1.x}{Python 2.2.0 to Python 2.2.1}{\emph{no longer supported}}
|
||||
\lineiii{2.5}{Python 2.2.2+ and Python 2.3}{Python 2.1 to 2.5}
|
||||
\lineiii{3.0}{Python 2.4}{Python 2.3 to 2.5}
|
||||
\lineiii{4.0}{Python 2.5}{Python 2.3 to 2.5}
|
||||
\end{tableiii}
|
||||
|
||||
Here are the differences between \module{email} version 3 and version 2:
|
||||
Here are the major differences between \module{email} verson 4 and version 3:
|
||||
|
||||
\begin{itemize}
|
||||
\item All modules have been renamed according to \pep{8} standards. For
|
||||
example, the version 3 module \module{email.Message} was renamed to
|
||||
\module{email.message} in version 4.
|
||||
|
||||
\item A new subpackage \module{email.mime} was added and all the version 3
|
||||
\module{email.MIME*} modules were renamed and situated into the
|
||||
\module{email.mime} subpackage. For example, the version 3 module
|
||||
\module{email.MIMEText} was renamed to \module{email.mime.text}.
|
||||
|
||||
\emph{Note that the version 3 names will continue to work until Python
|
||||
2.6}.
|
||||
|
||||
\item The \module{email.mime.application} module was added, which contains the
|
||||
\class{MIMEApplication} class.
|
||||
|
||||
\item Methods that were deprecated in version 3 have been removed. These
|
||||
include \method{Generator.__call__()}, \method{Message.get_type()},
|
||||
\method{Message.get_main_type()}, \method{Message.get_subtype()}.
|
||||
\end{itemize}
|
||||
|
||||
Here are the major differences between \module{email} version 3 and version 2:
|
||||
|
||||
\begin{itemize}
|
||||
\item The \class{FeedParser} class was introduced, and the \class{Parser}
|
||||
class was implemented in terms of the \class{FeedParser}. All parsing
|
||||
there for is non-strict, and parsing will make a best effort never to
|
||||
therefore is non-strict, and parsing will make a best effort never to
|
||||
raise an exception. Problems found while parsing messages are stored in
|
||||
the message's \var{defect} attribute.
|
||||
|
||||
|
@ -117,7 +147,7 @@ Here are the differences between \module{email} version 3 and version 2:
|
|||
\method{Generator.__call__()}, \method{Message.get_type()},
|
||||
\method{Message.get_main_type()}, \method{Message.get_subtype()}, and
|
||||
the \var{strict} argument to the \class{Parser} class. These are
|
||||
expected to be removed in email 3.1.
|
||||
expected to be removed in future versions.
|
||||
|
||||
\item Support for Pythons earlier than 2.3 has been removed.
|
||||
\end{itemize}
|
||||
|
@ -278,12 +308,12 @@ The \class{Message} class has the following differences:
|
|||
\item The method \method{getpayloadastext()} was removed. Similar
|
||||
functionality
|
||||
is supported by the \class{DecodedGenerator} class in the
|
||||
\refmodule{email.Generator} module.
|
||||
\refmodule{email.generator} module.
|
||||
|
||||
\item The method \method{getbodyastext()} was removed. You can get
|
||||
similar functionality by creating an iterator with
|
||||
\function{typed_subpart_iterator()} in the
|
||||
\refmodule{email.Iterators} module.
|
||||
\refmodule{email.iterators} module.
|
||||
\end{itemize}
|
||||
|
||||
The \class{Parser} class has no differences in its public interface.
|
||||
|
@ -295,7 +325,7 @@ notification\footnote{Delivery Status Notifications (DSN) are defined
|
|||
in \rfc{1894}.}.
|
||||
|
||||
The \class{Generator} class has no differences in its public
|
||||
interface. There is a new class in the \refmodule{email.Generator}
|
||||
interface. There is a new class in the \refmodule{email.generator}
|
||||
module though, called \class{DecodedGenerator} which provides most of
|
||||
the functionality previously available in the
|
||||
\method{Message.getpayloadastext()} method.
|
||||
|
@ -329,11 +359,11 @@ The following modules and classes have been changed:
|
|||
|
||||
\module{mimelib} provided some utility functions in its
|
||||
\module{address} and \module{date} modules. All of these functions
|
||||
have been moved to the \refmodule{email.Utils} module.
|
||||
have been moved to the \refmodule{email.utils} module.
|
||||
|
||||
The \code{MsgReader} class/module has been removed. Its functionality
|
||||
is most closely supported in the \function{body_line_iterator()}
|
||||
function in the \refmodule{email.Iterators} module.
|
||||
function in the \refmodule{email.iterators} module.
|
||||
|
||||
\subsection{Examples}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
\declaremodule{standard}{email.Charset}
|
||||
\declaremodule{standard}{email.charset}
|
||||
\modulesynopsis{Character Sets}
|
||||
|
||||
This module provides a class \class{Charset} for representing
|
||||
|
@ -7,6 +7,8 @@ well as a character set registry and several convenience methods for
|
|||
manipulating this registry. Instances of \class{Charset} are used in
|
||||
several other modules within the \module{email} package.
|
||||
|
||||
Import this class from the \module{email.charset} module.
|
||||
|
||||
\versionadded{2.2.2}
|
||||
|
||||
\begin{classdesc}{Charset}{\optional{input_charset}}
|
||||
|
@ -153,7 +155,7 @@ input charset to the output charset automatically. This is not useful
|
|||
for multibyte character sets, which have line length issues (multibyte
|
||||
characters must be split on a character, not a byte boundary); use the
|
||||
higher-level \class{Header} class to deal with these issues (see
|
||||
\refmodule{email.Header}). \var{convert} defaults to \code{False}.
|
||||
\refmodule{email.header}). \var{convert} defaults to \code{False}.
|
||||
|
||||
The type of encoding (base64 or quoted-printable) will be based on
|
||||
the \var{header_encoding} attribute.
|
||||
|
@ -188,7 +190,7 @@ This method allows you to compare two \class{Charset} instances for equality.
|
|||
This method allows you to compare two \class{Charset} instances for inequality.
|
||||
\end{methoddesc}
|
||||
|
||||
The \module{email.Charset} module also provides the following
|
||||
The \module{email.charset} module also provides the following
|
||||
functions for adding new entries to the global character set, alias,
|
||||
and codec registries:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
\declaremodule{standard}{email.Encoders}
|
||||
\declaremodule{standard}{email.encoders}
|
||||
\modulesynopsis{Encoders for email message payloads.}
|
||||
|
||||
When creating \class{Message} objects from scratch, you often need to
|
||||
|
@ -7,7 +7,7 @@ This is especially true for \mimetype{image/*} and \mimetype{text/*}
|
|||
type messages containing binary data.
|
||||
|
||||
The \module{email} package provides some convenient encodings in its
|
||||
\module{Encoders} module. These encoders are actually used by the
|
||||
\module{encoders} module. These encoders are actually used by the
|
||||
\class{MIMEAudio} and \class{MIMEImage} class constructors to provide default
|
||||
encodings. All encoder functions take exactly one argument, the message
|
||||
object to encode. They usually extract the payload, encode it, and reset the
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
\declaremodule{standard}{email.Errors}
|
||||
\declaremodule{standard}{email.errors}
|
||||
\modulesynopsis{The exception classes used by the email package.}
|
||||
|
||||
The following exception classes are defined in the
|
||||
\module{email.Errors} module:
|
||||
\module{email.errors} module:
|
||||
|
||||
\begin{excclassdesc}{MessageError}{}
|
||||
This is the base class for all exceptions that the \module{email}
|
||||
|
@ -59,7 +59,7 @@ problem was found, so for example, if a message nested inside a
|
|||
\mimetype{multipart/alternative} had a malformed header, that nested message
|
||||
object would have a defect, but the containing messages would not.
|
||||
|
||||
All defect classes are subclassed from \class{email.Errors.MessageDefect}, but
|
||||
All defect classes are subclassed from \class{email.errors.MessageDefect}, but
|
||||
this class is \emph{not} an exception!
|
||||
|
||||
\versionadded[All the defect classes were added]{2.4}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
\declaremodule{standard}{email.Generator}
|
||||
\declaremodule{standard}{email.generator}
|
||||
\modulesynopsis{Generate flat text email messages from a message structure.}
|
||||
|
||||
One of the most common tasks is to generate the flat text of the email
|
||||
|
@ -8,7 +8,7 @@ module or the \refmodule{nntplib} module, or print the message on the
|
|||
console. Taking a message object structure and producing a flat text
|
||||
document is the job of the \class{Generator} class.
|
||||
|
||||
Again, as with the \refmodule{email.Parser} module, you aren't limited
|
||||
Again, as with the \refmodule{email.parser} module, you aren't limited
|
||||
to the functionality of the bundled generator; you could write one
|
||||
from scratch yourself. However the bundled generator knows how to
|
||||
generate most email in a standards-compliant way, should handle MIME
|
||||
|
@ -17,7 +17,8 @@ transformation from flat text, to a message structure via the
|
|||
\class{Parser} class, and back to flat text, is idempotent (the input
|
||||
is identical to the output).
|
||||
|
||||
Here are the public methods of the \class{Generator} class:
|
||||
Here are the public methods of the \class{Generator} class, imported from the
|
||||
\module{email.generator} module:
|
||||
|
||||
\begin{classdesc}{Generator}{outfp\optional{, mangle_from_\optional{,
|
||||
maxheaderlen}}}
|
||||
|
@ -40,7 +41,7 @@ mailbox format files.
|
|||
Optional \var{maxheaderlen} specifies the longest length for a
|
||||
non-continued header. When a header line is longer than
|
||||
\var{maxheaderlen} (in characters, with tabs expanded to 8 spaces),
|
||||
the header will be split as defined in the \module{email.Header}
|
||||
the header will be split as defined in the \module{email.header.Header}
|
||||
class. Set to zero to disable header wrapping. The default is 78, as
|
||||
recommended (but not required) by \rfc{2822}.
|
||||
\end{classdesc}
|
||||
|
@ -81,9 +82,9 @@ be used in extended print statements.
|
|||
As a convenience, see the methods \method{Message.as_string()} and
|
||||
\code{str(aMessage)}, a.k.a. \method{Message.__str__()}, which
|
||||
simplify the generation of a formatted string representation of a
|
||||
message object. For more detail, see \refmodule{email.Message}.
|
||||
message object. For more detail, see \refmodule{email.message}.
|
||||
|
||||
The \module{email.Generator} module also provides a derived class,
|
||||
The \module{email.generator} module also provides a derived class,
|
||||
called \class{DecodedGenerator} which is like the \class{Generator}
|
||||
base class, except that non-\mimetype{text} parts are substituted with
|
||||
a format string representing the part.
|
||||
|
@ -128,13 +129,5 @@ The default value for \var{fmt} is \code{None}, meaning
|
|||
\versionadded{2.2.2}
|
||||
\end{classdesc}
|
||||
|
||||
\subsubsection{Deprecated methods}
|
||||
|
||||
The following methods are deprecated in \module{email} version 2.
|
||||
They are documented here for completeness.
|
||||
|
||||
\begin{methoddesc}[Generator]{__call__}{msg\optional{, unixfrom}}
|
||||
This method is identical to the \method{flatten()} method.
|
||||
|
||||
\deprecated{2.2.2}{Use the \method{flatten()} method instead.}
|
||||
\end{methoddesc}
|
||||
\versionchanged[The previously deprecated method \method{__call__()} was
|
||||
removed]{2.5}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
\declaremodule{standard}{email.Header}
|
||||
\declaremodule{standard}{email.header}
|
||||
\modulesynopsis{Representing non-ASCII headers}
|
||||
|
||||
\rfc{2822} is the base standard that describes the format of email
|
||||
|
@ -15,17 +15,18 @@ slew of RFCs have been written describing how to encode email
|
|||
containing non-\ASCII{} characters into \rfc{2822}-compliant format.
|
||||
These RFCs include \rfc{2045}, \rfc{2046}, \rfc{2047}, and \rfc{2231}.
|
||||
The \module{email} package supports these standards in its
|
||||
\module{email.Header} and \module{email.Charset} modules.
|
||||
\module{email.header} and \module{email.charset} modules.
|
||||
|
||||
If you want to include non-\ASCII{} characters in your email headers,
|
||||
say in the \mailheader{Subject} or \mailheader{To} fields, you should
|
||||
use the \class{Header} class and assign the field in the
|
||||
\class{Message} object to an instance of \class{Header} instead of
|
||||
using a string for the header value. For example:
|
||||
using a string for the header value. Import the \class{Header} class from the
|
||||
\module{email.header} module. For example:
|
||||
|
||||
\begin{verbatim}
|
||||
>>> from email.Message import Message
|
||||
>>> from email.Header import Header
|
||||
>>> from email.message import Message
|
||||
>>> from email.header import Header
|
||||
>>> msg = Message()
|
||||
>>> h = Header('p\xf6stal', 'iso-8859-1')
|
||||
>>> msg['Subject'] = h
|
||||
|
@ -87,7 +88,7 @@ Optional \var{errors} is passed straight through to the
|
|||
Append the string \var{s} to the MIME header.
|
||||
|
||||
Optional \var{charset}, if given, should be a \class{Charset} instance
|
||||
(see \refmodule{email.Charset}) or the name of a character set, which
|
||||
(see \refmodule{email.charset}) or the name of a character set, which
|
||||
will be converted to a \class{Charset} instance. A value of
|
||||
\code{None} (the default) means that the \var{charset} given in the
|
||||
constructor is used.
|
||||
|
@ -139,7 +140,7 @@ This method allows you to compare two \class{Header} instances for equality.
|
|||
This method allows you to compare two \class{Header} instances for inequality.
|
||||
\end{methoddesc}
|
||||
|
||||
The \module{email.Header} module also provides the following
|
||||
The \module{email.header} module also provides the following
|
||||
convenient functions.
|
||||
|
||||
\begin{funcdesc}{decode_header}{header}
|
||||
|
@ -155,7 +156,7 @@ encoded string.
|
|||
Here's an example:
|
||||
|
||||
\begin{verbatim}
|
||||
>>> from email.Header import decode_header
|
||||
>>> from email.header import decode_header
|
||||
>>> decode_header('=?iso-8859-1?q?p=F6stal?=')
|
||||
[('p\xf6stal', 'iso-8859-1')]
|
||||
\end{verbatim}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
\declaremodule{standard}{email.Iterators}
|
||||
\declaremodule{standard}{email.iterators}
|
||||
\modulesynopsis{Iterate over a message object tree.}
|
||||
|
||||
Iterating over a message object tree is fairly easy with the
|
||||
\method{Message.walk()} method. The \module{email.Iterators} module
|
||||
\method{Message.walk()} method. The \module{email.iterators} module
|
||||
provides some useful higher level iterations over message object
|
||||
trees.
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
\declaremodule{standard}{email.Message}
|
||||
\declaremodule{standard}{email.message}
|
||||
\modulesynopsis{The base class representing email messages.}
|
||||
|
||||
The central class in the \module{email} package is the
|
||||
\class{Message} class; it is the base class for the \module{email}
|
||||
object model. \class{Message} provides the core functionality for
|
||||
setting and querying header fields, and for accessing message bodies.
|
||||
\class{Message} class, imported from the \module{email.message} module. It is
|
||||
the base class for the \module{email} object model. \class{Message} provides
|
||||
the core functionality for setting and querying header fields, and for
|
||||
accessing message bodies.
|
||||
|
||||
Conceptually, a \class{Message} object consists of \emph{headers} and
|
||||
\emph{payloads}. Headers are \rfc{2822} style field names and
|
||||
|
@ -45,7 +46,7 @@ begin with \code{From }. For more flexibility, instantiate a
|
|||
|
||||
\begin{verbatim}
|
||||
from cStringIO import StringIO
|
||||
from email.Generator import Generator
|
||||
from email.generator import Generator
|
||||
fp = StringIO()
|
||||
g = Generator(fp, mangle_from_=False, maxheaderlen=60)
|
||||
g.flatten(msg)
|
||||
|
@ -119,7 +120,7 @@ client's responsibility to ensure the payload invariants. Optional
|
|||
|
||||
\begin{methoddesc}[Message]{set_charset}{charset}
|
||||
Set the character set of the payload to \var{charset}, which can
|
||||
either be a \class{Charset} instance (see \refmodule{email.Charset}), a
|
||||
either be a \class{Charset} instance (see \refmodule{email.charset}), a
|
||||
string naming a character set,
|
||||
or \code{None}. If it is a string, it will be converted to a
|
||||
\class{Charset} instance. If \var{charset} is \code{None}, the
|
||||
|
@ -128,8 +129,8 @@ or \code{None}. If it is a string, it will be converted to a
|
|||
\exception{TypeError}.
|
||||
|
||||
The message will be assumed to be of type \mimetype{text/*} encoded with
|
||||
\code{charset.input_charset}. It will be converted to
|
||||
\code{charset.output_charset}
|
||||
\var{charset.input_charset}. It will be converted to
|
||||
\var{charset.output_charset}
|
||||
and encoded properly, if needed, when generating the plain text
|
||||
representation of the message. MIME headers
|
||||
(\mailheader{MIME-Version}, \mailheader{Content-Type},
|
||||
|
@ -513,6 +514,9 @@ message/rfc822
|
|||
\end{verbatim}
|
||||
\end{methoddesc}
|
||||
|
||||
\versionchanged[The previously deprecated methods \method{get_type()},
|
||||
\method{get_main_type()}, and \method{get_subtype()} were removed]{2.5}
|
||||
|
||||
\class{Message} objects can also optionally contain two instance
|
||||
attributes, which can be used when generating the plain text of a MIME
|
||||
message.
|
||||
|
@ -532,7 +536,7 @@ to the message's \var{preamble} attribute. When the \class{Generator}
|
|||
is writing out the plain text representation of a MIME message, and it
|
||||
finds the message has a \var{preamble} attribute, it will write this
|
||||
text in the area between the headers and the first boundary. See
|
||||
\refmodule{email.Parser} and \refmodule{email.Generator} for details.
|
||||
\refmodule{email.parser} and \refmodule{email.generator} for details.
|
||||
|
||||
Note that if the message object has no preamble, the
|
||||
\var{preamble} attribute will be \code{None}.
|
||||
|
@ -543,58 +547,15 @@ The \var{epilogue} attribute acts the same way as the \var{preamble}
|
|||
attribute, except that it contains text that appears between the last
|
||||
boundary and the end of the message.
|
||||
|
||||
One note: when generating the flat text for a \mimetype{multipart}
|
||||
message that has no \var{epilogue} (using the standard
|
||||
\class{Generator} class), no newline is added after the closing
|
||||
boundary line. If the message object has an \var{epilogue} and its
|
||||
value does not start with a newline, a newline is printed after the
|
||||
closing boundary. This seems a little clumsy, but it makes the most
|
||||
practical sense. The upshot is that if you want to ensure that a
|
||||
newline get printed after your closing \mimetype{multipart} boundary,
|
||||
set the \var{epilogue} to the empty string.
|
||||
\versionchanged[You do not need to set the epilogue to the empty string in
|
||||
order for the \class{Generator} to print a newline at the end of the
|
||||
file]{2.5}
|
||||
\end{datadesc}
|
||||
|
||||
\begin{datadesc}{defects}
|
||||
The \var{defects} attribute contains a list of all the problems found when
|
||||
parsing this message. See \refmodule{email.Errors} for a detailed description
|
||||
parsing this message. See \refmodule{email.errors} for a detailed description
|
||||
of the possible parsing defects.
|
||||
|
||||
\versionadded{2.4}
|
||||
\end{datadesc}
|
||||
|
||||
\subsubsection{Deprecated methods}
|
||||
|
||||
\versionchanged[The \method{add_payload()} method was removed; use the
|
||||
\method{attach()} method instead]{2.4}
|
||||
|
||||
The following methods are deprecated. They are documented here for
|
||||
completeness.
|
||||
|
||||
\begin{methoddesc}[Message]{get_type}{\optional{failobj}}
|
||||
Return the message's content type, as a string of the form
|
||||
\mimetype{maintype/subtype} as taken from the
|
||||
\mailheader{Content-Type} header.
|
||||
The returned string is coerced to lowercase.
|
||||
|
||||
If there is no \mailheader{Content-Type} header in the message,
|
||||
\var{failobj} is returned (defaults to \code{None}).
|
||||
|
||||
\deprecated{2.2.2}{Use the \method{get_content_type()} method instead.}
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}[Message]{get_main_type}{\optional{failobj}}
|
||||
Return the message's \emph{main} content type. This essentially returns the
|
||||
\var{maintype} part of the string returned by \method{get_type()}, with the
|
||||
same semantics for \var{failobj}.
|
||||
|
||||
\deprecated{2.2.2}{Use the \method{get_content_maintype()} method instead.}
|
||||
\end{methoddesc}
|
||||
|
||||
\begin{methoddesc}[Message]{get_subtype}{\optional{failobj}}
|
||||
Return the message's sub-content type. This essentially returns the
|
||||
\var{subtype} part of the string returned by \method{get_type()}, with the
|
||||
same semantics for \var{failobj}.
|
||||
|
||||
\deprecated{2.2.2}{Use the \method{get_content_subtype()} method instead.}
|
||||
\end{methoddesc}
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
\declaremodule{standard}{email.mime}
|
||||
\declaremodule{standard}{email.mime.base}
|
||||
\declaremodule{standard}{email.mime.nonmultipart}
|
||||
\declaremodule{standard}{email.mime.multipart}
|
||||
\declaremodule{standard}{email.mime.audio}
|
||||
\declaremodule{standard}{email.mime.image}
|
||||
\declaremodule{standard}{email.mime.message}
|
||||
\declaremodule{standard}{email.mime.text}
|
||||
Ordinarily, you get a message object structure by passing a file or
|
||||
some text to a parser, which parses the text and returns the root
|
||||
message object. However you can also build a complete message
|
||||
|
@ -6,26 +14,16 @@ hand. In fact, you can also take an existing structure and add new
|
|||
\class{Message} objects, move them around, etc. This makes a very
|
||||
convenient interface for slicing-and-dicing MIME messages.
|
||||
|
||||
You can create a new object structure by creating \class{Message}
|
||||
instances, adding attachments and all the appropriate headers manually.
|
||||
For MIME messages though, the \module{email} package provides some
|
||||
convenient subclasses to make things easier. Each of these classes
|
||||
should be imported from a module with the same name as the class, from
|
||||
within the \module{email} package. E.g.:
|
||||
|
||||
\begin{verbatim}
|
||||
import email.MIMEImage.MIMEImage
|
||||
\end{verbatim}
|
||||
|
||||
or
|
||||
|
||||
\begin{verbatim}
|
||||
from email.MIMEText import MIMEText
|
||||
\end{verbatim}
|
||||
You can create a new object structure by creating \class{Message} instances,
|
||||
adding attachments and all the appropriate headers manually. For MIME
|
||||
messages though, the \module{email} package provides some convenient
|
||||
subclasses to make things easier.
|
||||
|
||||
Here are the classes:
|
||||
|
||||
\begin{classdesc}{MIMEBase}{_maintype, _subtype, **_params}
|
||||
Module: \module{email.mime.base}
|
||||
|
||||
This is the base class for all the MIME-specific subclasses of
|
||||
\class{Message}. Ordinarily you won't create instances specifically
|
||||
of \class{MIMEBase}, although you could. \class{MIMEBase} is provided
|
||||
|
@ -45,6 +43,8 @@ The \class{MIMEBase} class always adds a \mailheader{Content-Type} header
|
|||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMENonMultipart}{}
|
||||
Module: \module{email.mime.nonmultipart}
|
||||
|
||||
A subclass of \class{MIMEBase}, this is an intermediate base class for
|
||||
MIME messages that are not \mimetype{multipart}. The primary purpose
|
||||
of this class is to prevent the use of the \method{attach()} method,
|
||||
|
@ -57,6 +57,7 @@ exception is raised.
|
|||
|
||||
\begin{classdesc}{MIMEMultipart}{\optional{subtype\optional{,
|
||||
boundary\optional{, _subparts\optional{, _params}}}}}
|
||||
Module: \module{email.mime.multipart}
|
||||
|
||||
A subclass of \class{MIMEBase}, this is an intermediate base class for
|
||||
MIME messages that are \mimetype{multipart}. Optional \var{_subtype}
|
||||
|
@ -80,8 +81,31 @@ argument, which is a keyword dictionary.
|
|||
\versionadded{2.2.2}
|
||||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMEApplication}{_data\optional{, _subtype\optional{,
|
||||
_encoder\optional{, **_params}}}}
|
||||
Module: \module{email.mime.application}
|
||||
|
||||
A subclass of \class{MIMENonMultipart}, the \class{MIMEApplication} class is
|
||||
used to represent MIME message objects of major type \mimetype{application}.
|
||||
\var{_data} is a string containing the raw byte data. Optional \var{_subtype}
|
||||
specifies the MIME subtype and defaults to \mimetype{octet-stream}.
|
||||
|
||||
Optional \var{_encoder} is a callable (i.e. function) which will
|
||||
perform the actual encoding of the data for transport. This
|
||||
callable takes one argument, which is the \class{MIMEApplication} instance.
|
||||
It should use \method{get_payload()} and \method{set_payload()} to
|
||||
change the payload to encoded form. It should also add any
|
||||
\mailheader{Content-Transfer-Encoding} or other headers to the message
|
||||
object as necessary. The default encoding is base64. See the
|
||||
\refmodule{email.encoders} module for a list of the built-in encoders.
|
||||
|
||||
\var{_params} are passed straight through to the base class constructor.
|
||||
\versionadded{2.5}
|
||||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMEAudio}{_audiodata\optional{, _subtype\optional{,
|
||||
_encoder\optional{, **_params}}}}
|
||||
Module: \module{email.mime.audio}
|
||||
|
||||
A subclass of \class{MIMENonMultipart}, the \class{MIMEAudio} class
|
||||
is used to create MIME message objects of major type \mimetype{audio}.
|
||||
|
@ -100,13 +124,14 @@ It should use \method{get_payload()} and \method{set_payload()} to
|
|||
change the payload to encoded form. It should also add any
|
||||
\mailheader{Content-Transfer-Encoding} or other headers to the message
|
||||
object as necessary. The default encoding is base64. See the
|
||||
\refmodule{email.Encoders} module for a list of the built-in encoders.
|
||||
\refmodule{email.encoders} module for a list of the built-in encoders.
|
||||
|
||||
\var{_params} are passed straight through to the base class constructor.
|
||||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMEImage}{_imagedata\optional{, _subtype\optional{,
|
||||
_encoder\optional{, **_params}}}}
|
||||
Module: \module{email.mime.image}
|
||||
|
||||
A subclass of \class{MIMENonMultipart}, the \class{MIMEImage} class is
|
||||
used to create MIME message objects of major type \mimetype{image}.
|
||||
|
@ -125,13 +150,15 @@ It should use \method{get_payload()} and \method{set_payload()} to
|
|||
change the payload to encoded form. It should also add any
|
||||
\mailheader{Content-Transfer-Encoding} or other headers to the message
|
||||
object as necessary. The default encoding is base64. See the
|
||||
\refmodule{email.Encoders} module for a list of the built-in encoders.
|
||||
\refmodule{email.encoders} module for a list of the built-in encoders.
|
||||
|
||||
\var{_params} are passed straight through to the \class{MIMEBase}
|
||||
constructor.
|
||||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMEMessage}{_msg\optional{, _subtype}}
|
||||
Module: \module{email.mime.message}
|
||||
|
||||
A subclass of \class{MIMENonMultipart}, the \class{MIMEMessage} class
|
||||
is used to create MIME objects of main type \mimetype{message}.
|
||||
\var{_msg} is used as the payload, and must be an instance of class
|
||||
|
@ -143,6 +170,8 @@ to \mimetype{rfc822}.
|
|||
\end{classdesc}
|
||||
|
||||
\begin{classdesc}{MIMEText}{_text\optional{, _subtype\optional{, _charset}}}
|
||||
Module: \module{email.mime.text}
|
||||
|
||||
A subclass of \class{MIMENonMultipart}, the \class{MIMEText} class is
|
||||
used to create MIME objects of major type \mimetype{text}.
|
||||
\var{_text} is the string for the payload. \var{_subtype} is the
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
\declaremodule{standard}{email.Parser}
|
||||
\declaremodule{standard}{email.parser}
|
||||
\modulesynopsis{Parse flat text email messages to produce a message
|
||||
object structure.}
|
||||
|
||||
|
@ -41,9 +41,10 @@ message object trees any way it finds necessary.
|
|||
|
||||
\versionadded{2.4}
|
||||
|
||||
The \class{FeedParser} provides an API that is conducive to incremental
|
||||
parsing of email messages, such as would be necessary when reading the text of
|
||||
an email message from a source that can block (e.g. a socket). The
|
||||
The \class{FeedParser}, imported from the \module{email.feedparser} module,
|
||||
provides an API that is conducive to incremental parsing of email messages,
|
||||
such as would be necessary when reading the text of an email message from a
|
||||
source that can block (e.g. a socket). The
|
||||
\class{FeedParser} can of course be used to parse an email message fully
|
||||
contained in a string or a file, but the classic \class{Parser} API may be
|
||||
more convenient for such use cases. The semantics and results of the two
|
||||
|
@ -56,14 +57,14 @@ accurate when parsing standards-compliant messages, and it does a very good
|
|||
job of parsing non-compliant messages, providing information about how a
|
||||
message was deemed broken. It will populate a message object's \var{defects}
|
||||
attribute with a list of any problems it found in a message. See the
|
||||
\refmodule{email.Errors} module for the list of defects that it can find.
|
||||
\refmodule{email.errors} module for the list of defects that it can find.
|
||||
|
||||
Here is the API for the \class{FeedParser}:
|
||||
|
||||
\begin{classdesc}{FeedParser}{\optional{_factory}}
|
||||
Create a \class{FeedParser} instance. Optional \var{_factory} is a
|
||||
no-argument callable that will be called whenever a new message object is
|
||||
needed. It defaults to the \class{email.Message.Message} class.
|
||||
needed. It defaults to the \class{email.message.Message} class.
|
||||
\end{classdesc}
|
||||
|
||||
\begin{methoddesc}[FeedParser]{feed}{data}
|
||||
|
@ -82,21 +83,22 @@ more data to a closed \class{FeedParser}.
|
|||
|
||||
\subsubsection{Parser class API}
|
||||
|
||||
The \class{Parser} provides an API that can be used to parse a message when
|
||||
the complete contents of the message are available in a string or file. The
|
||||
\module{email.Parser} module also provides a second class, called
|
||||
The \class{Parser} class, imported from the \module{email.parser} module,
|
||||
provides an API that can be used to parse a message when the complete contents
|
||||
of the message are available in a string or file. The
|
||||
\module{email.parser} module also provides a second class, called
|
||||
\class{HeaderParser} which can be used if you're only interested in
|
||||
the headers of the message. \class{HeaderParser} can be much faster in
|
||||
these situations, since it does not attempt to parse the message body,
|
||||
instead setting the payload to the raw body as a string.
|
||||
\class{HeaderParser} has the same API as the \class{Parser} class.
|
||||
|
||||
\begin{classdesc}{Parser}{\optional{_class\optional{, strict}}}
|
||||
\begin{classdesc}{Parser}{\optional{_class}}
|
||||
The constructor for the \class{Parser} class takes an optional
|
||||
argument \var{_class}. This must be a callable factory (such as a
|
||||
function or a class), and it is used whenever a sub-message object
|
||||
needs to be created. It defaults to \class{Message} (see
|
||||
\refmodule{email.Message}). The factory will be called without
|
||||
\refmodule{email.message}). The factory will be called without
|
||||
arguments.
|
||||
|
||||
The optional \var{strict} flag is ignored. \deprecated{2.4}{Because the
|
||||
|
@ -201,6 +203,6 @@ Here are some notes on the parsing semantics:
|
|||
\method{is_multipart()} method may return \code{False}. If such
|
||||
messages were parsed with the \class{FeedParser}, they will have an
|
||||
instance of the \class{MultipartInvariantViolationDefect} class in their
|
||||
\var{defects} attribute list. See \refmodule{email.Errors} for
|
||||
\var{defects} attribute list. See \refmodule{email.errors} for
|
||||
details.
|
||||
\end{itemize}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
\declaremodule{standard}{email.Utils}
|
||||
\declaremodule{standard}{email.utils}
|
||||
\modulesynopsis{Miscellaneous email package utilities.}
|
||||
|
||||
There are several useful utilities provided in the \module{email.Utils}
|
||||
There are several useful utilities provided in the \module{email.utils}
|
||||
module:
|
||||
|
||||
\begin{funcdesc}{quote}{str}
|
||||
|
@ -38,7 +38,7 @@ values as might be returned by \method{Message.get_all()}. Here's a
|
|||
simple example that gets all the recipients of a message:
|
||||
|
||||
\begin{verbatim}
|
||||
from email.Utils import getaddresses
|
||||
from email.utils import getaddresses
|
||||
|
||||
tos = msg.get_all('to', [])
|
||||
ccs = msg.get_all('cc', [])
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
\authoraddress{\email{barry@python.org}}
|
||||
|
||||
\date{\today}
|
||||
\release{3.0} % software release, not documentation
|
||||
\release{4.0} % software release, not documentation
|
||||
\setreleaseinfo{} % empty for final release
|
||||
\setshortversion{3.0} % major.minor only for software
|
||||
\setshortversion{4.0} % major.minor only for software
|
||||
|
||||
\begin{document}
|
||||
|
||||
|
@ -38,11 +38,11 @@ The \module{email} package provides classes and utilities to create,
|
|||
parse, generate, and modify email messages, conforming to all the
|
||||
relevant email and MIME related RFCs.
|
||||
|
||||
This document describes version 3.0 of the \module{email} package, which is
|
||||
distributed with Python 2.4 and is available as a standalone distutils-based
|
||||
package for use with Python 2.3. \module{email} 3.0 is not compatible with
|
||||
Python versions earlier than 2.3. For more information about the
|
||||
\module{email} package, including download links and mailing lists, see
|
||||
This document describes version 4.0 of the \module{email} package, which is
|
||||
distributed with Python 2.5 and is available as a standalone distutils-based
|
||||
package for use with earlier Python versions. \module{email} 4.0 is not
|
||||
compatible with Python versions earlier than 2.3. For more information about
|
||||
the \module{email} package, including download links and mailing lists, see
|
||||
\ulink{Python's email SIG}{http://www.python.org/sigs/email-sig}.
|
||||
|
||||
The documentation that follows was written for the Python project, so
|
||||
|
@ -51,7 +51,8 @@ package documentation, there are a few notes to be aware of:
|
|||
|
||||
\begin{itemize}
|
||||
\item Deprecation and ``version added'' notes are relative to the
|
||||
Python version a feature was added or deprecated.
|
||||
Python version a feature was added or deprecated. See
|
||||
the package history in section \ref{email-pkg-history} for details.
|
||||
|
||||
\item If you're reading this documentation as part of the
|
||||
standalone \module{email} package, some of the internal links to
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
"""A package for parsing, handling, and generating email messages."""
|
||||
|
||||
__version__ = '3.0.1'
|
||||
__version__ = '4.0a2'
|
||||
|
||||
__all__ = [
|
||||
# Old names
|
||||
'base64MIME',
|
||||
'Charset',
|
||||
'Encoders',
|
||||
|
@ -27,6 +28,19 @@ __all__ = [
|
|||
'Utils',
|
||||
'message_from_string',
|
||||
'message_from_file',
|
||||
# new names
|
||||
'base64mime',
|
||||
'charset',
|
||||
'encoders',
|
||||
'errors',
|
||||
'generator',
|
||||
'header',
|
||||
'iterators',
|
||||
'message',
|
||||
'mime',
|
||||
'parser',
|
||||
'quoprimime',
|
||||
'utils',
|
||||
]
|
||||
|
||||
|
||||
|
@ -39,7 +53,7 @@ def message_from_string(s, *args, **kws):
|
|||
|
||||
Optional _class and strict are passed to the Parser constructor.
|
||||
"""
|
||||
from email.Parser import Parser
|
||||
from email.parser import Parser
|
||||
return Parser(*args, **kws).parsestr(s)
|
||||
|
||||
|
||||
|
@ -48,5 +62,62 @@ def message_from_file(fp, *args, **kws):
|
|||
|
||||
Optional _class and strict are passed to the Parser constructor.
|
||||
"""
|
||||
from email.Parser import Parser
|
||||
from email.parser import Parser
|
||||
return Parser(*args, **kws).parse(fp)
|
||||
|
||||
|
||||
|
||||
# Lazy loading to provide name mapping from new-style names (PEP 8 compatible
|
||||
# email 4.0 module names), to old-style names (email 3.0 module names).
|
||||
import sys
|
||||
|
||||
class LazyImporter(object):
|
||||
def __init__(self, module_name):
|
||||
self.__name__ = 'email.' + module_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
__import__(self.__name__)
|
||||
mod = sys.modules[self.__name__]
|
||||
self.__dict__.update(mod.__dict__)
|
||||
return getattr(mod, name)
|
||||
|
||||
|
||||
_LOWERNAMES = [
|
||||
# email.<old name> -> email.<new name is lowercased old name>
|
||||
'Charset',
|
||||
'Encoders',
|
||||
'Errors',
|
||||
'FeedParser',
|
||||
'Generator',
|
||||
'Header',
|
||||
'Iterators',
|
||||
'Message',
|
||||
'Parser',
|
||||
'Utils',
|
||||
'base64MIME',
|
||||
'quopriMIME',
|
||||
]
|
||||
|
||||
_MIMENAMES = [
|
||||
# email.MIME<old name> -> email.mime.<new name is lowercased old name>
|
||||
'Audio',
|
||||
'Base',
|
||||
'Image',
|
||||
'Message',
|
||||
'Multipart',
|
||||
'NonMultipart',
|
||||
'Text',
|
||||
]
|
||||
|
||||
for _name in _LOWERNAMES:
|
||||
importer = LazyImporter(_name.lower())
|
||||
sys.modules['email.' + _name] = importer
|
||||
setattr(sys.modules['email'], _name, importer)
|
||||
|
||||
|
||||
import email.mime
|
||||
for _name in _MIMENAMES:
|
||||
importer = LazyImporter('mime.' + _name.lower())
|
||||
sys.modules['email.MIME' + _name] = importer
|
||||
setattr(sys.modules['email'], 'MIME' + _name, importer)
|
||||
setattr(sys.modules['email.mime'], _name, importer)
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
Lifted directly from rfc822.py. This should eventually be rewritten.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'mktime_tz',
|
||||
'parsedate',
|
||||
'parsedate_tz',
|
||||
'quote',
|
||||
]
|
||||
|
||||
import time
|
||||
|
||||
SPACE = ' '
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2002-2004 Python Software Foundation
|
||||
# Copyright (C) 2002-2006 Python Software Foundation
|
||||
# Author: Ben Gertzfield
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
|
@ -24,9 +24,21 @@ decoding. To deal with the various line wrapping issues, use the email.Header
|
|||
module.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'base64_len',
|
||||
'body_decode',
|
||||
'body_encode',
|
||||
'decode',
|
||||
'decodestring',
|
||||
'encode',
|
||||
'encodestring',
|
||||
'header_encode',
|
||||
]
|
||||
|
||||
import re
|
||||
|
||||
from binascii import b2a_base64, a2b_base64
|
||||
from email.Utils import fix_eols
|
||||
from email.utils import fix_eols
|
||||
|
||||
CRLF = '\r\n'
|
||||
NL = '\n'
|
|
@ -2,9 +2,18 @@
|
|||
# Author: Ben Gertzfield, Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
import email.base64MIME
|
||||
import email.quopriMIME
|
||||
from email.Encoders import encode_7or8bit
|
||||
__all__ = [
|
||||
'Charset',
|
||||
'add_alias',
|
||||
'add_charset',
|
||||
'add_codec',
|
||||
]
|
||||
|
||||
import email.base64mime
|
||||
import email.quoprimime
|
||||
|
||||
from email import errors
|
||||
from email.encoders import encode_7or8bit
|
||||
|
||||
|
||||
|
||||
|
@ -186,8 +195,17 @@ class Charset:
|
|||
"""
|
||||
def __init__(self, input_charset=DEFAULT_CHARSET):
|
||||
# RFC 2046, $4.1.2 says charsets are not case sensitive. We coerce to
|
||||
# unicode because its .lower() is locale insensitive.
|
||||
input_charset = unicode(input_charset, 'ascii').lower()
|
||||
# unicode because its .lower() is locale insensitive. If the argument
|
||||
# is already a unicode, we leave it at that, but ensure that the
|
||||
# charset is ASCII, as the standard (RFC XXX) requires.
|
||||
try:
|
||||
if isinstance(input_charset, unicode):
|
||||
input_charset.encode('ascii')
|
||||
else:
|
||||
input_charset = unicode(input_charset, 'ascii')
|
||||
except UnicodeError:
|
||||
raise errors.CharsetError(input_charset)
|
||||
input_charset = input_charset.lower()
|
||||
# Set the input charset after filtering through the aliases
|
||||
self.input_charset = ALIASES.get(input_charset, input_charset)
|
||||
# We can try to guess which encoding and conversion to use by the
|
||||
|
@ -307,12 +325,12 @@ class Charset:
|
|||
cset = self.get_output_charset()
|
||||
# The len(s) of a 7bit encoding is len(s)
|
||||
if self.header_encoding == BASE64:
|
||||
return email.base64MIME.base64_len(s) + len(cset) + MISC_LEN
|
||||
return email.base64mime.base64_len(s) + len(cset) + MISC_LEN
|
||||
elif self.header_encoding == QP:
|
||||
return email.quopriMIME.header_quopri_len(s) + len(cset) + MISC_LEN
|
||||
return email.quoprimime.header_quopri_len(s) + len(cset) + MISC_LEN
|
||||
elif self.header_encoding == SHORTEST:
|
||||
lenb64 = email.base64MIME.base64_len(s)
|
||||
lenqp = email.quopriMIME.header_quopri_len(s)
|
||||
lenb64 = email.base64mime.base64_len(s)
|
||||
lenqp = email.quoprimime.header_quopri_len(s)
|
||||
return min(lenb64, lenqp) + len(cset) + MISC_LEN
|
||||
else:
|
||||
return len(s)
|
||||
|
@ -335,16 +353,16 @@ class Charset:
|
|||
s = self.convert(s)
|
||||
# 7bit/8bit encodings return the string unchanged (modulo conversions)
|
||||
if self.header_encoding == BASE64:
|
||||
return email.base64MIME.header_encode(s, cset)
|
||||
return email.base64mime.header_encode(s, cset)
|
||||
elif self.header_encoding == QP:
|
||||
return email.quopriMIME.header_encode(s, cset, maxlinelen=None)
|
||||
return email.quoprimime.header_encode(s, cset, maxlinelen=None)
|
||||
elif self.header_encoding == SHORTEST:
|
||||
lenb64 = email.base64MIME.base64_len(s)
|
||||
lenqp = email.quopriMIME.header_quopri_len(s)
|
||||
lenb64 = email.base64mime.base64_len(s)
|
||||
lenqp = email.quoprimime.header_quopri_len(s)
|
||||
if lenb64 < lenqp:
|
||||
return email.base64MIME.header_encode(s, cset)
|
||||
return email.base64mime.header_encode(s, cset)
|
||||
else:
|
||||
return email.quopriMIME.header_encode(s, cset, maxlinelen=None)
|
||||
return email.quoprimime.header_encode(s, cset, maxlinelen=None)
|
||||
else:
|
||||
return s
|
||||
|
||||
|
@ -363,8 +381,8 @@ class Charset:
|
|||
s = self.convert(s)
|
||||
# 7bit/8bit encodings return the string unchanged (module conversions)
|
||||
if self.body_encoding is BASE64:
|
||||
return email.base64MIME.body_encode(s)
|
||||
return email.base64mime.body_encode(s)
|
||||
elif self.body_encoding is QP:
|
||||
return email.quopriMIME.body_encode(s)
|
||||
return email.quoprimime.body_encode(s)
|
||||
else:
|
||||
return s
|
|
@ -1,12 +1,22 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Encodings and related functions."""
|
||||
|
||||
__all__ = [
|
||||
'encode_7or8bit',
|
||||
'encode_base64',
|
||||
'encode_noop',
|
||||
'encode_quopri',
|
||||
]
|
||||
|
||||
import base64
|
||||
|
||||
from quopri import encodestring as _encodestring
|
||||
|
||||
|
||||
|
||||
def _qencode(s):
|
||||
enc = _encodestring(s, quotetabs=True)
|
||||
# Must encode spaces, which quopri.encodestring() doesn't do
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
|
@ -26,6 +26,10 @@ class MultipartConversionError(MessageError, TypeError):
|
|||
"""Conversion to a multipart is prohibited."""
|
||||
|
||||
|
||||
class CharsetError(MessageError):
|
||||
"""An illegal charset was given."""
|
||||
|
||||
|
||||
|
||||
# These are parsing defects which the parser was able to work around.
|
||||
class MessageDefect:
|
|
@ -19,9 +19,12 @@ the current message. Defects are just instances that live on the message
|
|||
object's .defects attribute.
|
||||
"""
|
||||
|
||||
__all__ = ['FeedParser']
|
||||
|
||||
import re
|
||||
from email import Errors
|
||||
from email import Message
|
||||
|
||||
from email import errors
|
||||
from email import message
|
||||
|
||||
NLCRE = re.compile('\r\n|\r|\n')
|
||||
NLCRE_bol = re.compile('(\r\n|\r|\n)')
|
||||
|
@ -130,7 +133,7 @@ class BufferedSubFile(object):
|
|||
class FeedParser:
|
||||
"""A feed-style parser of email."""
|
||||
|
||||
def __init__(self, _factory=Message.Message):
|
||||
def __init__(self, _factory=message.Message):
|
||||
"""_factory is called with no arguments to create a new message obj"""
|
||||
self._factory = _factory
|
||||
self._input = BufferedSubFile()
|
||||
|
@ -164,7 +167,7 @@ class FeedParser:
|
|||
# Look for final set of defects
|
||||
if root.get_content_maintype() == 'multipart' \
|
||||
and not root.is_multipart():
|
||||
root.defects.append(Errors.MultipartInvariantViolationDefect())
|
||||
root.defects.append(errors.MultipartInvariantViolationDefect())
|
||||
return root
|
||||
|
||||
def _new_message(self):
|
||||
|
@ -277,7 +280,7 @@ class FeedParser:
|
|||
# defined a boundary. That's a problem which we'll handle by
|
||||
# reading everything until the EOF and marking the message as
|
||||
# defective.
|
||||
self._cur.defects.append(Errors.NoBoundaryInMultipartDefect())
|
||||
self._cur.defects.append(errors.NoBoundaryInMultipartDefect())
|
||||
lines = []
|
||||
for line in self._input:
|
||||
if line is NeedMoreData:
|
||||
|
@ -381,7 +384,7 @@ class FeedParser:
|
|||
# that as a defect and store the captured text as the payload.
|
||||
# Everything from here to the EOF is epilogue.
|
||||
if capturing_preamble:
|
||||
self._cur.defects.append(Errors.StartBoundaryNotFoundDefect())
|
||||
self._cur.defects.append(errors.StartBoundaryNotFoundDefect())
|
||||
self._cur.set_payload(EMPTYSTRING.join(preamble))
|
||||
epilogue = []
|
||||
for line in self._input:
|
||||
|
@ -432,7 +435,7 @@ class FeedParser:
|
|||
# The first line of the headers was a continuation. This
|
||||
# is illegal, so let's note the defect, store the illegal
|
||||
# line, and ignore it for purposes of headers.
|
||||
defect = Errors.FirstHeaderLineIsContinuationDefect(line)
|
||||
defect = errors.FirstHeaderLineIsContinuationDefect(line)
|
||||
self._cur.defects.append(defect)
|
||||
continue
|
||||
lastvalue.append(line)
|
||||
|
@ -460,13 +463,13 @@ class FeedParser:
|
|||
else:
|
||||
# Weirdly placed unix-from line. Note this as a defect
|
||||
# and ignore it.
|
||||
defect = Errors.MisplacedEnvelopeHeaderDefect(line)
|
||||
defect = errors.MisplacedEnvelopeHeaderDefect(line)
|
||||
self._cur.defects.append(defect)
|
||||
continue
|
||||
# Split the line on the colon separating field name from value.
|
||||
i = line.find(':')
|
||||
if i < 0:
|
||||
defect = Errors.MalformedHeaderDefect(line)
|
||||
defect = errors.MalformedHeaderDefect(line)
|
||||
self._cur.defects.append(defect)
|
||||
continue
|
||||
lastheader = line[:i]
|
|
@ -4,14 +4,16 @@
|
|||
|
||||
"""Classes to generate plain text from a message object tree."""
|
||||
|
||||
__all__ = ['Generator', 'DecodedGenerator']
|
||||
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import warnings
|
||||
from cStringIO import StringIO
|
||||
|
||||
from email.Header import Header
|
||||
from cStringIO import StringIO
|
||||
from email.header import Header
|
||||
|
||||
UNDERSCORE = '_'
|
||||
NL = '\n'
|
||||
|
@ -81,12 +83,6 @@ class Generator:
|
|||
print >> self._fp, ufrom
|
||||
self._write(msg)
|
||||
|
||||
# For backwards compatibility, but this is slower
|
||||
def __call__(self, msg, unixfrom=False):
|
||||
warnings.warn('__call__() deprecated; use flatten()',
|
||||
DeprecationWarning, 2)
|
||||
self.flatten(msg, unixfrom)
|
||||
|
||||
def clone(self, fp):
|
||||
"""Clone this generator with the exact same options."""
|
||||
return self.__class__(fp, self._mangle_from_, self._maxheaderlen)
|
|
@ -1,16 +1,23 @@
|
|||
# Copyright (C) 2002-2004 Python Software Foundation
|
||||
# Copyright (C) 2002-2006 Python Software Foundation
|
||||
# Author: Ben Gertzfield, Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Header encoding and decoding functionality."""
|
||||
|
||||
__all__ = [
|
||||
'Header',
|
||||
'decode_header',
|
||||
'make_header',
|
||||
]
|
||||
|
||||
import re
|
||||
import binascii
|
||||
|
||||
import email.quopriMIME
|
||||
import email.base64MIME
|
||||
from email.Errors import HeaderParseError
|
||||
from email.Charset import Charset
|
||||
import email.quoprimime
|
||||
import email.base64mime
|
||||
|
||||
from email.errors import HeaderParseError
|
||||
from email.charset import Charset
|
||||
|
||||
NL = '\n'
|
||||
SPACE = ' '
|
||||
|
@ -42,7 +49,7 @@ fcre = re.compile(r'[\041-\176]+:$')
|
|||
|
||||
|
||||
# Helpers
|
||||
_max_append = email.quopriMIME._max_append
|
||||
_max_append = email.quoprimime._max_append
|
||||
|
||||
|
||||
|
||||
|
@ -82,10 +89,10 @@ def decode_header(header):
|
|||
encoded = parts[2]
|
||||
dec = None
|
||||
if encoding == 'q':
|
||||
dec = email.quopriMIME.header_decode(encoded)
|
||||
dec = email.quoprimime.header_decode(encoded)
|
||||
elif encoding == 'b':
|
||||
try:
|
||||
dec = email.base64MIME.decode(encoded)
|
||||
dec = email.base64mime.decode(encoded)
|
||||
except binascii.Error:
|
||||
# Turn this into a higher level exception. BAW: Right
|
||||
# now we throw the lower level exception away but
|
|
@ -1,9 +1,16 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Various types of useful iterators and generators."""
|
||||
|
||||
__all__ = [
|
||||
'body_line_iterator',
|
||||
'typed_subpart_iterator',
|
||||
'walk',
|
||||
# Do not include _structure() since it's part of the debugging API.
|
||||
]
|
||||
|
||||
import sys
|
||||
from cStringIO import StringIO
|
||||
|
||||
|
@ -25,7 +32,6 @@ def walk(self):
|
|||
|
||||
|
||||
# These two functions are imported into the Iterators.py interface module.
|
||||
# The Python 2.2 version uses generators for efficiency.
|
||||
def body_line_iterator(msg, decode=False):
|
||||
"""Iterate over the parts, returning string payloads line-by-line.
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
"""Basic message object for the email package object model."""
|
||||
|
||||
__all__ = ['Message']
|
||||
|
||||
import re
|
||||
import uu
|
||||
import binascii
|
||||
|
@ -11,9 +13,9 @@ import warnings
|
|||
from cStringIO import StringIO
|
||||
|
||||
# Intrapackage imports
|
||||
from email import Utils
|
||||
from email import Errors
|
||||
from email import Charset
|
||||
import email.charset
|
||||
from email import utils
|
||||
from email import errors
|
||||
|
||||
SEMISPACE = '; '
|
||||
|
||||
|
@ -41,11 +43,11 @@ def _formatparam(param, value=None, quote=True):
|
|||
if isinstance(value, tuple):
|
||||
# Encode as per RFC 2231
|
||||
param += '*'
|
||||
value = Utils.encode_rfc2231(value[2], value[0], value[1])
|
||||
value = utils.encode_rfc2231(value[2], value[0], value[1])
|
||||
# BAW: Please check this. I think that if quote is set it should
|
||||
# force quoting even if not necessary.
|
||||
if quote or tspecials.search(value):
|
||||
return '%s="%s"' % (param, Utils.quote(value))
|
||||
return '%s="%s"' % (param, utils.quote(value))
|
||||
else:
|
||||
return '%s=%s' % (param, value)
|
||||
else:
|
||||
|
@ -70,14 +72,14 @@ def _parseparam(s):
|
|||
|
||||
|
||||
def _unquotevalue(value):
|
||||
# This is different than Utils.collapse_rfc2231_value() because it doesn't
|
||||
# This is different than utils.collapse_rfc2231_value() because it doesn't
|
||||
# try to convert the value to a unicode. Message.get_param() and
|
||||
# Message.get_params() are both currently defined to return the tuple in
|
||||
# the face of RFC 2231 parameters.
|
||||
if isinstance(value, tuple):
|
||||
return value[0], value[1], Utils.unquote(value[2])
|
||||
return value[0], value[1], utils.unquote(value[2])
|
||||
else:
|
||||
return Utils.unquote(value)
|
||||
return utils.unquote(value)
|
||||
|
||||
|
||||
|
||||
|
@ -188,17 +190,17 @@ class Message:
|
|||
return None
|
||||
cte = self.get('content-transfer-encoding', '').lower()
|
||||
if cte == 'quoted-printable':
|
||||
return Utils._qdecode(payload)
|
||||
return utils._qdecode(payload)
|
||||
elif cte == 'base64':
|
||||
try:
|
||||
return Utils._bdecode(payload)
|
||||
return utils._bdecode(payload)
|
||||
except binascii.Error:
|
||||
# Incorrect padding
|
||||
return payload
|
||||
elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
|
||||
sfp = StringIO()
|
||||
try:
|
||||
uu.decode(StringIO(payload+'\n'), sfp)
|
||||
uu.decode(StringIO(payload+'\n'), sfp, quiet=True)
|
||||
payload = sfp.getvalue()
|
||||
except uu.Error:
|
||||
# Some decoding problem
|
||||
|
@ -237,8 +239,8 @@ class Message:
|
|||
self._charset = None
|
||||
return
|
||||
if isinstance(charset, str):
|
||||
charset = Charset.Charset(charset)
|
||||
if not isinstance(charset, Charset.Charset):
|
||||
charset = email.charset.Charset(charset)
|
||||
if not isinstance(charset, email.charset.Charset):
|
||||
raise TypeError(charset)
|
||||
# BAW: should we accept strings that can serve as arguments to the
|
||||
# Charset constructor?
|
||||
|
@ -412,49 +414,6 @@ class Message:
|
|||
else:
|
||||
raise KeyError(_name)
|
||||
|
||||
#
|
||||
# Deprecated methods. These will be removed in email 3.1.
|
||||
#
|
||||
|
||||
def get_type(self, failobj=None):
|
||||
"""Returns the message's content type.
|
||||
|
||||
The returned string is coerced to lowercase and returned as a single
|
||||
string of the form `maintype/subtype'. If there was no Content-Type
|
||||
header in the message, failobj is returned (defaults to None).
|
||||
"""
|
||||
warnings.warn('get_type() deprecated; use get_content_type()',
|
||||
DeprecationWarning, 2)
|
||||
missing = object()
|
||||
value = self.get('content-type', missing)
|
||||
if value is missing:
|
||||
return failobj
|
||||
return paramre.split(value)[0].lower().strip()
|
||||
|
||||
def get_main_type(self, failobj=None):
|
||||
"""Return the message's main content type if present."""
|
||||
warnings.warn('get_main_type() deprecated; use get_content_maintype()',
|
||||
DeprecationWarning, 2)
|
||||
missing = object()
|
||||
ctype = self.get_type(missing)
|
||||
if ctype is missing:
|
||||
return failobj
|
||||
if ctype.count('/') <> 1:
|
||||
return failobj
|
||||
return ctype.split('/')[0]
|
||||
|
||||
def get_subtype(self, failobj=None):
|
||||
"""Return the message's content subtype if present."""
|
||||
warnings.warn('get_subtype() deprecated; use get_content_subtype()',
|
||||
DeprecationWarning, 2)
|
||||
missing = object()
|
||||
ctype = self.get_type(missing)
|
||||
if ctype is missing:
|
||||
return failobj
|
||||
if ctype.count('/') <> 1:
|
||||
return failobj
|
||||
return ctype.split('/')[1]
|
||||
|
||||
#
|
||||
# Use these three methods instead of the three above.
|
||||
#
|
||||
|
@ -537,7 +496,7 @@ class Message:
|
|||
name = p.strip()
|
||||
val = ''
|
||||
params.append((name, val))
|
||||
params = Utils.decode_params(params)
|
||||
params = utils.decode_params(params)
|
||||
return params
|
||||
|
||||
def get_params(self, failobj=None, header='content-type', unquote=True):
|
||||
|
@ -714,7 +673,7 @@ class Message:
|
|||
filename = self.get_param('name', missing, 'content-disposition')
|
||||
if filename is missing:
|
||||
return failobj
|
||||
return Utils.collapse_rfc2231_value(filename).strip()
|
||||
return utils.collapse_rfc2231_value(filename).strip()
|
||||
|
||||
def get_boundary(self, failobj=None):
|
||||
"""Return the boundary associated with the payload if present.
|
||||
|
@ -727,7 +686,7 @@ class Message:
|
|||
if boundary is missing:
|
||||
return failobj
|
||||
# RFC 2046 says that boundaries may begin but not end in w/s
|
||||
return Utils.collapse_rfc2231_value(boundary).rstrip()
|
||||
return utils.collapse_rfc2231_value(boundary).rstrip()
|
||||
|
||||
def set_boundary(self, boundary):
|
||||
"""Set the boundary parameter in Content-Type to 'boundary'.
|
||||
|
@ -744,7 +703,7 @@ class Message:
|
|||
if params is missing:
|
||||
# There was no Content-Type header, and we don't know what type
|
||||
# to set it to, so raise an exception.
|
||||
raise Errors.HeaderParseError, 'No Content-Type header found'
|
||||
raise errors.HeaderParseError('No Content-Type header found')
|
||||
newparams = []
|
||||
foundp = False
|
||||
for pk, pv in params:
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Keith Dart
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Class representing application/* type MIME documents."""
|
||||
|
||||
__all__ = ["MIMEApplication"]
|
||||
|
||||
from email import encoders
|
||||
from email.mime.nonmultipart import MIMENonMultipart
|
||||
|
||||
|
||||
class MIMEApplication(MIMENonMultipart):
|
||||
"""Class for generating application/* MIME documents."""
|
||||
|
||||
def __init__(self, _data, _subtype='octet-stream',
|
||||
_encoder=encoders.encode_base64, **_params):
|
||||
"""Create an application/* type MIME document.
|
||||
|
||||
_data is a string containing the raw applicatoin data.
|
||||
|
||||
_subtype is the MIME content type subtype, defaulting to
|
||||
'octet-stream'.
|
||||
|
||||
_encoder is a function which will perform the actual encoding for
|
||||
transport of the application data, defaulting to base64 encoding.
|
||||
|
||||
Any additional keyword arguments are passed to the base class
|
||||
constructor, which turns them into parameters on the Content-Type
|
||||
header.
|
||||
"""
|
||||
if _subtype is None:
|
||||
raise TypeError('Invalid application MIME subtype')
|
||||
MIMENonMultipart.__init__(self, 'application', _subtype, **_params)
|
||||
self.set_payload(_data)
|
||||
_encoder(self)
|
|
@ -1,15 +1,16 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Anthony Baxter
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Class representing audio/* type MIME documents."""
|
||||
|
||||
import sndhdr
|
||||
from cStringIO import StringIO
|
||||
__all__ = ['MIMEAudio']
|
||||
|
||||
from email import Errors
|
||||
from email import Encoders
|
||||
from email.MIMENonMultipart import MIMENonMultipart
|
||||
import sndhdr
|
||||
|
||||
from cStringIO import StringIO
|
||||
from email import encoders
|
||||
from email.mime.nonmultipart import MIMENonMultipart
|
||||
|
||||
|
||||
|
||||
|
@ -42,7 +43,7 @@ class MIMEAudio(MIMENonMultipart):
|
|||
"""Class for generating audio/* MIME documents."""
|
||||
|
||||
def __init__(self, _audiodata, _subtype=None,
|
||||
_encoder=Encoders.encode_base64, **_params):
|
||||
_encoder=encoders.encode_base64, **_params):
|
||||
"""Create an audio/* type MIME document.
|
||||
|
||||
_audiodata is a string containing the raw audio data. If this data
|
|
@ -1,14 +1,16 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Base class for MIME specializations."""
|
||||
|
||||
from email import Message
|
||||
__all__ = ['MIMEBase']
|
||||
|
||||
from email import message
|
||||
|
||||
|
||||
|
||||
class MIMEBase(Message.Message):
|
||||
class MIMEBase(message.Message):
|
||||
"""Base class for MIME specializations."""
|
||||
|
||||
def __init__(self, _maintype, _subtype, **_params):
|
||||
|
@ -18,7 +20,7 @@ class MIMEBase(Message.Message):
|
|||
arguments. Additional parameters for this header are taken from the
|
||||
keyword arguments.
|
||||
"""
|
||||
Message.Message.__init__(self)
|
||||
message.Message.__init__(self)
|
||||
ctype = '%s/%s' % (_maintype, _subtype)
|
||||
self.add_header('Content-Type', ctype, **_params)
|
||||
self['MIME-Version'] = '1.0'
|
|
@ -1,14 +1,15 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Class representing image/* type MIME documents."""
|
||||
|
||||
__all__ = ['MIMEImage']
|
||||
|
||||
import imghdr
|
||||
|
||||
from email import Errors
|
||||
from email import Encoders
|
||||
from email.MIMENonMultipart import MIMENonMultipart
|
||||
from email import encoders
|
||||
from email.mime.nonmultipart import MIMENonMultipart
|
||||
|
||||
|
||||
|
||||
|
@ -16,7 +17,7 @@ class MIMEImage(MIMENonMultipart):
|
|||
"""Class for generating image/* type MIME documents."""
|
||||
|
||||
def __init__(self, _imagedata, _subtype=None,
|
||||
_encoder=Encoders.encode_base64, **_params):
|
||||
_encoder=encoders.encode_base64, **_params):
|
||||
"""Create an image/* type MIME document.
|
||||
|
||||
_imagedata is a string containing the raw image data. If this data
|
|
@ -1,11 +1,13 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Class representing message/* MIME documents."""
|
||||
|
||||
from email import Message
|
||||
from email.MIMENonMultipart import MIMENonMultipart
|
||||
__all__ = ['MIMEMessage']
|
||||
|
||||
from email import message
|
||||
from email.mime.nonmultipart import MIMENonMultipart
|
||||
|
||||
|
||||
|
||||
|
@ -23,10 +25,10 @@ class MIMEMessage(MIMENonMultipart):
|
|||
the term "rfc822" is technically outdated by RFC 2822).
|
||||
"""
|
||||
MIMENonMultipart.__init__(self, 'message', _subtype)
|
||||
if not isinstance(_msg, Message.Message):
|
||||
if not isinstance(_msg, message.Message):
|
||||
raise TypeError('Argument is not an instance of Message')
|
||||
# It's convenient to use this base class method. We need to do it
|
||||
# this way or we'll get an exception
|
||||
Message.Message.attach(self, _msg)
|
||||
message.Message.attach(self, _msg)
|
||||
# And be sure our default type is set correctly
|
||||
self.set_default_type('message/rfc822')
|
|
@ -1,14 +1,16 @@
|
|||
# Copyright (C) 2002-2004 Python Software Foundation
|
||||
# Copyright (C) 2002-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Base class for MIME multipart/* type messages."""
|
||||
|
||||
from email import MIMEBase
|
||||
__all__ = ['MIMEMultipart']
|
||||
|
||||
from email.mime.base import MIMEBase
|
||||
|
||||
|
||||
|
||||
class MIMEMultipart(MIMEBase.MIMEBase):
|
||||
class MIMEMultipart(MIMEBase):
|
||||
"""Base class for MIME multipart/* type messages."""
|
||||
|
||||
def __init__(self, _subtype='mixed', boundary=None, _subparts=None,
|
||||
|
@ -31,7 +33,7 @@ class MIMEMultipart(MIMEBase.MIMEBase):
|
|||
Additional parameters for the Content-Type header are taken from the
|
||||
keyword arguments (or passed into the _params argument).
|
||||
"""
|
||||
MIMEBase.MIMEBase.__init__(self, 'multipart', _subtype, **_params)
|
||||
MIMEBase.__init__(self, 'multipart', _subtype, **_params)
|
||||
if _subparts:
|
||||
for p in _subparts:
|
||||
self.attach(p)
|
|
@ -1,15 +1,17 @@
|
|||
# Copyright (C) 2002-2004 Python Software Foundation
|
||||
# Copyright (C) 2002-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Base class for MIME type messages that are not multipart."""
|
||||
|
||||
from email import Errors
|
||||
from email import MIMEBase
|
||||
__all__ = ['MIMENonMultipart']
|
||||
|
||||
from email import errors
|
||||
from email.mime.base import MIMEBase
|
||||
|
||||
|
||||
|
||||
class MIMENonMultipart(MIMEBase.MIMEBase):
|
||||
class MIMENonMultipart(MIMEBase):
|
||||
"""Base class for MIME multipart/* type messages."""
|
||||
|
||||
__pychecker__ = 'unusednames=payload'
|
||||
|
@ -18,7 +20,7 @@ class MIMENonMultipart(MIMEBase.MIMEBase):
|
|||
# The public API prohibits attaching multiple subparts to MIMEBase
|
||||
# derived subtypes since none of them are, by definition, of content
|
||||
# type multipart/*
|
||||
raise Errors.MultipartConversionError(
|
||||
raise errors.MultipartConversionError(
|
||||
'Cannot attach additional subparts to non-multipart/*')
|
||||
|
||||
del __pychecker__
|
|
@ -1,11 +1,13 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Class representing text/* type MIME documents."""
|
||||
|
||||
from email.MIMENonMultipart import MIMENonMultipart
|
||||
from email.Encoders import encode_7or8bit
|
||||
__all__ = ['MIMEText']
|
||||
|
||||
from email.encoders import encode_7or8bit
|
||||
from email.mime.nonmultipart import MIMENonMultipart
|
||||
|
||||
|
||||
|
|
@ -1,13 +1,16 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw, Thomas Wouters, Anthony Baxter
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""A parser of RFC 2822 and MIME email messages."""
|
||||
|
||||
__all__ = ['Parser', 'HeaderParser']
|
||||
|
||||
import warnings
|
||||
from cStringIO import StringIO
|
||||
from email.FeedParser import FeedParser
|
||||
from email.Message import Message
|
||||
|
||||
from email.feedparser import FeedParser
|
||||
from email.message import Message
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Ben Gertzfield
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
|
@ -26,9 +26,27 @@ does dumb encoding and decoding. To deal with the various line
|
|||
wrapping issues, use the email.Header module.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'body_decode',
|
||||
'body_encode',
|
||||
'body_quopri_check',
|
||||
'body_quopri_len',
|
||||
'decode',
|
||||
'decodestring',
|
||||
'encode',
|
||||
'encodestring',
|
||||
'header_decode',
|
||||
'header_encode',
|
||||
'header_quopri_check',
|
||||
'header_quopri_len',
|
||||
'quote',
|
||||
'unquote',
|
||||
]
|
||||
|
||||
import re
|
||||
|
||||
from string import hexdigits
|
||||
from email.Utils import fix_eols
|
||||
from email.utils import fix_eols
|
||||
|
||||
CRLF = '\r\n'
|
||||
NL = '\n'
|
|
@ -39,9 +39,6 @@ NL = '\n'
|
|||
EMPTYSTRING = ''
|
||||
SPACE = ' '
|
||||
|
||||
# We don't care about DeprecationWarnings
|
||||
warnings.filterwarnings('ignore', '', DeprecationWarning, __name__)
|
||||
|
||||
|
||||
|
||||
def openfile(filename, mode='r'):
|
||||
|
@ -87,7 +84,7 @@ class TestMessageAPI(TestEmailBase):
|
|||
charset = Charset('iso-8859-1')
|
||||
msg.set_charset(charset)
|
||||
eq(msg['mime-version'], '1.0')
|
||||
eq(msg.get_type(), 'text/plain')
|
||||
eq(msg.get_content_type(), 'text/plain')
|
||||
eq(msg['content-type'], 'text/plain; charset="iso-8859-1"')
|
||||
eq(msg.get_param('charset'), 'iso-8859-1')
|
||||
eq(msg['content-transfer-encoding'], 'quoted-printable')
|
||||
|
@ -211,6 +208,19 @@ class TestMessageAPI(TestEmailBase):
|
|||
msg.set_payload('foo')
|
||||
eq(msg.get_payload(decode=True), 'foo')
|
||||
|
||||
def test_decode_bogus_uu_payload_quietly(self):
|
||||
msg = Message()
|
||||
msg.set_payload('begin 664 foo.txt\n%<W1F=0000H \n \nend\n')
|
||||
msg['Content-Transfer-Encoding'] = 'x-uuencode'
|
||||
old_stderr = sys.stderr
|
||||
try:
|
||||
sys.stderr = sfp = StringIO()
|
||||
# We don't care about the payload
|
||||
msg.get_payload(decode=True)
|
||||
finally:
|
||||
sys.stderr = old_stderr
|
||||
self.assertEqual(sfp.getvalue(), '')
|
||||
|
||||
def test_decoded_generator(self):
|
||||
eq = self.assertEqual
|
||||
msg = self._msgobj('msg_07.txt')
|
||||
|
@ -893,7 +903,7 @@ class TestMIMEAudio(unittest.TestCase):
|
|||
self._au = MIMEAudio(self._audiodata)
|
||||
|
||||
def test_guess_minor_type(self):
|
||||
self.assertEqual(self._au.get_type(), 'audio/basic')
|
||||
self.assertEqual(self._au.get_content_type(), 'audio/basic')
|
||||
|
||||
def test_encoding(self):
|
||||
payload = self._au.get_payload()
|
||||
|
@ -901,7 +911,7 @@ class TestMIMEAudio(unittest.TestCase):
|
|||
|
||||
def test_checkSetMinor(self):
|
||||
au = MIMEAudio(self._audiodata, 'fish')
|
||||
self.assertEqual(au.get_type(), 'audio/fish')
|
||||
self.assertEqual(au.get_content_type(), 'audio/fish')
|
||||
|
||||
def test_add_header(self):
|
||||
eq = self.assertEqual
|
||||
|
@ -936,7 +946,7 @@ class TestMIMEImage(unittest.TestCase):
|
|||
self._im = MIMEImage(self._imgdata)
|
||||
|
||||
def test_guess_minor_type(self):
|
||||
self.assertEqual(self._im.get_type(), 'image/gif')
|
||||
self.assertEqual(self._im.get_content_type(), 'image/gif')
|
||||
|
||||
def test_encoding(self):
|
||||
payload = self._im.get_payload()
|
||||
|
@ -944,7 +954,7 @@ class TestMIMEImage(unittest.TestCase):
|
|||
|
||||
def test_checkSetMinor(self):
|
||||
im = MIMEImage(self._imgdata, 'fish')
|
||||
self.assertEqual(im.get_type(), 'image/fish')
|
||||
self.assertEqual(im.get_content_type(), 'image/fish')
|
||||
|
||||
def test_add_header(self):
|
||||
eq = self.assertEqual
|
||||
|
@ -976,7 +986,7 @@ class TestMIMEText(unittest.TestCase):
|
|||
def test_types(self):
|
||||
eq = self.assertEqual
|
||||
unless = self.failUnless
|
||||
eq(self._msg.get_type(), 'text/plain')
|
||||
eq(self._msg.get_content_type(), 'text/plain')
|
||||
eq(self._msg.get_param('charset'), 'us-ascii')
|
||||
missing = []
|
||||
unless(self._msg.get_param('foobar', missing) is missing)
|
||||
|
@ -1045,7 +1055,7 @@ This is the dingus fish.
|
|||
# tests
|
||||
m = self._msg
|
||||
unless(m.is_multipart())
|
||||
eq(m.get_type(), 'multipart/mixed')
|
||||
eq(m.get_content_type(), 'multipart/mixed')
|
||||
eq(len(m.get_payload()), 2)
|
||||
raises(IndexError, m.get_payload, 2)
|
||||
m0 = m.get_payload(0)
|
||||
|
@ -1379,7 +1389,7 @@ class TestNonConformant(TestEmailBase):
|
|||
def test_parse_missing_minor_type(self):
|
||||
eq = self.assertEqual
|
||||
msg = self._msgobj('msg_14.txt')
|
||||
eq(msg.get_type(), 'text')
|
||||
eq(msg.get_content_type(), 'text/plain')
|
||||
eq(msg.get_content_maintype(), 'text')
|
||||
eq(msg.get_content_subtype(), 'plain')
|
||||
|
||||
|
@ -1531,7 +1541,7 @@ class TestMIMEMessage(TestEmailBase):
|
|||
m = Message()
|
||||
m['Subject'] = subject
|
||||
r = MIMEMessage(m)
|
||||
eq(r.get_type(), 'message/rfc822')
|
||||
eq(r.get_content_type(), 'message/rfc822')
|
||||
payload = r.get_payload()
|
||||
unless(isinstance(payload, list))
|
||||
eq(len(payload), 1)
|
||||
|
@ -1572,7 +1582,7 @@ Here is the body of the message.
|
|||
eq = self.assertEqual
|
||||
unless = self.failUnless
|
||||
msg = self._msgobj('msg_11.txt')
|
||||
eq(msg.get_type(), 'message/rfc822')
|
||||
eq(msg.get_content_type(), 'message/rfc822')
|
||||
payload = msg.get_payload()
|
||||
unless(isinstance(payload, list))
|
||||
eq(len(payload), 1)
|
||||
|
@ -1586,12 +1596,12 @@ Here is the body of the message.
|
|||
unless = self.failUnless
|
||||
# msg 16 is a Delivery Status Notification, see RFC 1894
|
||||
msg = self._msgobj('msg_16.txt')
|
||||
eq(msg.get_type(), 'multipart/report')
|
||||
eq(msg.get_content_type(), 'multipart/report')
|
||||
unless(msg.is_multipart())
|
||||
eq(len(msg.get_payload()), 3)
|
||||
# Subpart 1 is a text/plain, human readable section
|
||||
subpart = msg.get_payload(0)
|
||||
eq(subpart.get_type(), 'text/plain')
|
||||
eq(subpart.get_content_type(), 'text/plain')
|
||||
eq(subpart.get_payload(), """\
|
||||
This report relates to a message you sent with the following header fields:
|
||||
|
||||
|
@ -1611,7 +1621,7 @@ Your message cannot be delivered to the following recipients:
|
|||
# consists of two blocks of headers, represented by two nested Message
|
||||
# objects.
|
||||
subpart = msg.get_payload(1)
|
||||
eq(subpart.get_type(), 'message/delivery-status')
|
||||
eq(subpart.get_content_type(), 'message/delivery-status')
|
||||
eq(len(subpart.get_payload()), 2)
|
||||
# message/delivery-status should treat each block as a bunch of
|
||||
# headers, i.e. a bunch of Message objects.
|
||||
|
@ -1629,13 +1639,13 @@ Your message cannot be delivered to the following recipients:
|
|||
eq(dsn2.get_param('rfc822', header='final-recipient'), '')
|
||||
# Subpart 3 is the original message
|
||||
subpart = msg.get_payload(2)
|
||||
eq(subpart.get_type(), 'message/rfc822')
|
||||
eq(subpart.get_content_type(), 'message/rfc822')
|
||||
payload = subpart.get_payload()
|
||||
unless(isinstance(payload, list))
|
||||
eq(len(payload), 1)
|
||||
subsubpart = payload[0]
|
||||
unless(isinstance(subsubpart, Message))
|
||||
eq(subsubpart.get_type(), 'text/plain')
|
||||
eq(subsubpart.get_content_type(), 'text/plain')
|
||||
eq(subsubpart['message-id'],
|
||||
'<002001c144a6$8752e060$56104586@oxy.edu>')
|
||||
|
||||
|
@ -1706,16 +1716,16 @@ Two
|
|||
fp.close()
|
||||
container1 = msg.get_payload(0)
|
||||
eq(container1.get_default_type(), 'message/rfc822')
|
||||
eq(container1.get_type(), None)
|
||||
eq(container1.get_content_type(), 'message/rfc822')
|
||||
container2 = msg.get_payload(1)
|
||||
eq(container2.get_default_type(), 'message/rfc822')
|
||||
eq(container2.get_type(), None)
|
||||
eq(container2.get_content_type(), 'message/rfc822')
|
||||
container1a = container1.get_payload(0)
|
||||
eq(container1a.get_default_type(), 'text/plain')
|
||||
eq(container1a.get_type(), 'text/plain')
|
||||
eq(container1a.get_content_type(), 'text/plain')
|
||||
container2a = container2.get_payload(0)
|
||||
eq(container2a.get_default_type(), 'text/plain')
|
||||
eq(container2a.get_type(), 'text/plain')
|
||||
eq(container2a.get_content_type(), 'text/plain')
|
||||
|
||||
def test_default_type_with_explicit_container_type(self):
|
||||
eq = self.assertEqual
|
||||
|
@ -1726,16 +1736,16 @@ Two
|
|||
fp.close()
|
||||
container1 = msg.get_payload(0)
|
||||
eq(container1.get_default_type(), 'message/rfc822')
|
||||
eq(container1.get_type(), 'message/rfc822')
|
||||
eq(container1.get_content_type(), 'message/rfc822')
|
||||
container2 = msg.get_payload(1)
|
||||
eq(container2.get_default_type(), 'message/rfc822')
|
||||
eq(container2.get_type(), 'message/rfc822')
|
||||
eq(container2.get_content_type(), 'message/rfc822')
|
||||
container1a = container1.get_payload(0)
|
||||
eq(container1a.get_default_type(), 'text/plain')
|
||||
eq(container1a.get_type(), 'text/plain')
|
||||
eq(container1a.get_content_type(), 'text/plain')
|
||||
container2a = container2.get_payload(0)
|
||||
eq(container2a.get_default_type(), 'text/plain')
|
||||
eq(container2a.get_type(), 'text/plain')
|
||||
eq(container2a.get_content_type(), 'text/plain')
|
||||
|
||||
def test_default_type_non_parsed(self):
|
||||
eq = self.assertEqual
|
||||
|
@ -1750,9 +1760,9 @@ Two
|
|||
subpart2 = MIMEMessage(subpart2a)
|
||||
container.attach(subpart1)
|
||||
container.attach(subpart2)
|
||||
eq(subpart1.get_type(), 'message/rfc822')
|
||||
eq(subpart1.get_content_type(), 'message/rfc822')
|
||||
eq(subpart1.get_default_type(), 'message/rfc822')
|
||||
eq(subpart2.get_type(), 'message/rfc822')
|
||||
eq(subpart2.get_content_type(), 'message/rfc822')
|
||||
eq(subpart2.get_default_type(), 'message/rfc822')
|
||||
neq(container.as_string(0), '''\
|
||||
Content-Type: multipart/digest; boundary="BOUNDARY"
|
||||
|
@ -1784,9 +1794,9 @@ message 2
|
|||
del subpart1['mime-version']
|
||||
del subpart2['content-type']
|
||||
del subpart2['mime-version']
|
||||
eq(subpart1.get_type(), None)
|
||||
eq(subpart1.get_content_type(), 'message/rfc822')
|
||||
eq(subpart1.get_default_type(), 'message/rfc822')
|
||||
eq(subpart2.get_type(), None)
|
||||
eq(subpart2.get_content_type(), 'message/rfc822')
|
||||
eq(subpart2.get_default_type(), 'message/rfc822')
|
||||
neq(container.as_string(0), '''\
|
||||
Content-Type: multipart/digest; boundary="BOUNDARY"
|
||||
|
@ -1847,7 +1857,7 @@ class TestIdempotent(TestEmailBase):
|
|||
def test_parse_text_message(self):
|
||||
eq = self.assertEquals
|
||||
msg, text = self._msgobj('msg_01.txt')
|
||||
eq(msg.get_type(), 'text/plain')
|
||||
eq(msg.get_content_type(), 'text/plain')
|
||||
eq(msg.get_content_maintype(), 'text')
|
||||
eq(msg.get_content_subtype(), 'plain')
|
||||
eq(msg.get_params()[1], ('charset', 'us-ascii'))
|
||||
|
@ -1859,7 +1869,7 @@ class TestIdempotent(TestEmailBase):
|
|||
def test_parse_untyped_message(self):
|
||||
eq = self.assertEquals
|
||||
msg, text = self._msgobj('msg_03.txt')
|
||||
eq(msg.get_type(), None)
|
||||
eq(msg.get_content_type(), 'text/plain')
|
||||
eq(msg.get_params(), None)
|
||||
eq(msg.get_param('charset'), None)
|
||||
self._idempotent(msg, text)
|
||||
|
@ -1933,7 +1943,7 @@ class TestIdempotent(TestEmailBase):
|
|||
unless = self.failUnless
|
||||
# Get a message object and reset the seek pointer for other tests
|
||||
msg, text = self._msgobj('msg_05.txt')
|
||||
eq(msg.get_type(), 'multipart/report')
|
||||
eq(msg.get_content_type(), 'multipart/report')
|
||||
# Test the Content-Type: parameters
|
||||
params = {}
|
||||
for pk, pv in msg.get_params():
|
||||
|
@ -1945,13 +1955,13 @@ class TestIdempotent(TestEmailBase):
|
|||
eq(len(msg.get_payload()), 3)
|
||||
# Make sure the subparts are what we expect
|
||||
msg1 = msg.get_payload(0)
|
||||
eq(msg1.get_type(), 'text/plain')
|
||||
eq(msg1.get_content_type(), 'text/plain')
|
||||
eq(msg1.get_payload(), 'Yadda yadda yadda\n')
|
||||
msg2 = msg.get_payload(1)
|
||||
eq(msg2.get_type(), None)
|
||||
eq(msg2.get_content_type(), 'text/plain')
|
||||
eq(msg2.get_payload(), 'Yadda yadda yadda\n')
|
||||
msg3 = msg.get_payload(2)
|
||||
eq(msg3.get_type(), 'message/rfc822')
|
||||
eq(msg3.get_content_type(), 'message/rfc822')
|
||||
self.failUnless(isinstance(msg3, Message))
|
||||
payload = msg3.get_payload()
|
||||
unless(isinstance(payload, list))
|
||||
|
@ -1965,7 +1975,7 @@ class TestIdempotent(TestEmailBase):
|
|||
unless = self.failUnless
|
||||
msg, text = self._msgobj('msg_06.txt')
|
||||
# Check some of the outer headers
|
||||
eq(msg.get_type(), 'message/rfc822')
|
||||
eq(msg.get_content_type(), 'message/rfc822')
|
||||
# Make sure the payload is a list of exactly one sub-Message, and that
|
||||
# that submessage has a type of text/plain
|
||||
payload = msg.get_payload()
|
||||
|
@ -1973,7 +1983,7 @@ class TestIdempotent(TestEmailBase):
|
|||
eq(len(payload), 1)
|
||||
msg1 = payload[0]
|
||||
self.failUnless(isinstance(msg1, Message))
|
||||
eq(msg1.get_type(), 'text/plain')
|
||||
eq(msg1.get_content_type(), 'text/plain')
|
||||
self.failUnless(isinstance(msg1.get_payload(), str))
|
||||
eq(msg1.get_payload(), '\n')
|
||||
|
||||
|
@ -2058,13 +2068,19 @@ class TestMiscellaneous(TestEmailBase):
|
|||
module = __import__('email')
|
||||
all = module.__all__
|
||||
all.sort()
|
||||
self.assertEqual(all, ['Charset', 'Encoders', 'Errors', 'Generator',
|
||||
'Header', 'Iterators', 'MIMEAudio', 'MIMEBase',
|
||||
'MIMEImage', 'MIMEMessage', 'MIMEMultipart',
|
||||
'MIMENonMultipart', 'MIMEText', 'Message',
|
||||
'Parser', 'Utils', 'base64MIME',
|
||||
'message_from_file', 'message_from_string',
|
||||
'quopriMIME'])
|
||||
self.assertEqual(all, [
|
||||
# Old names
|
||||
'Charset', 'Encoders', 'Errors', 'Generator',
|
||||
'Header', 'Iterators', 'MIMEAudio', 'MIMEBase',
|
||||
'MIMEImage', 'MIMEMessage', 'MIMEMultipart',
|
||||
'MIMENonMultipart', 'MIMEText', 'Message',
|
||||
'Parser', 'Utils', 'base64MIME',
|
||||
# new names
|
||||
'base64mime', 'charset', 'encoders', 'errors', 'generator',
|
||||
'header', 'iterators', 'message', 'message_from_file',
|
||||
'message_from_string', 'mime', 'parser',
|
||||
'quopriMIME', 'quoprimime', 'utils',
|
||||
])
|
||||
|
||||
def test_formatdate(self):
|
||||
now = time.time()
|
||||
|
@ -2356,7 +2372,7 @@ class TestParsers(TestEmailBase):
|
|||
fp.close()
|
||||
eq(msg['from'], 'ppp-request@zzz.org')
|
||||
eq(msg['to'], 'ppp@zzz.org')
|
||||
eq(msg.get_type(), 'multipart/mixed')
|
||||
eq(msg.get_content_type(), 'multipart/mixed')
|
||||
self.failIf(msg.is_multipart())
|
||||
self.failUnless(isinstance(msg.get_payload(), str))
|
||||
|
||||
|
@ -2405,10 +2421,10 @@ Here's the message body
|
|||
fp.close()
|
||||
eq(len(msg.get_payload()), 2)
|
||||
part1 = msg.get_payload(0)
|
||||
eq(part1.get_type(), 'text/plain')
|
||||
eq(part1.get_content_type(), 'text/plain')
|
||||
eq(part1.get_payload(), 'Simple email with attachment.\r\n\r\n')
|
||||
part2 = msg.get_payload(1)
|
||||
eq(part2.get_type(), 'application/riscos')
|
||||
eq(part2.get_content_type(), 'application/riscos')
|
||||
|
||||
def test_multipart_digest_with_extra_mime_headers(self):
|
||||
eq = self.assertEqual
|
||||
|
@ -2427,21 +2443,21 @@ Here's the message body
|
|||
eq(msg.is_multipart(), 1)
|
||||
eq(len(msg.get_payload()), 2)
|
||||
part1 = msg.get_payload(0)
|
||||
eq(part1.get_type(), 'message/rfc822')
|
||||
eq(part1.get_content_type(), 'message/rfc822')
|
||||
eq(part1.is_multipart(), 1)
|
||||
eq(len(part1.get_payload()), 1)
|
||||
part1a = part1.get_payload(0)
|
||||
eq(part1a.is_multipart(), 0)
|
||||
eq(part1a.get_type(), 'text/plain')
|
||||
eq(part1a.get_content_type(), 'text/plain')
|
||||
neq(part1a.get_payload(), 'message 1\n')
|
||||
# next message/rfc822
|
||||
part2 = msg.get_payload(1)
|
||||
eq(part2.get_type(), 'message/rfc822')
|
||||
eq(part2.get_content_type(), 'message/rfc822')
|
||||
eq(part2.is_multipart(), 1)
|
||||
eq(len(part2.get_payload()), 1)
|
||||
part2a = part2.get_payload(0)
|
||||
eq(part2a.is_multipart(), 0)
|
||||
eq(part2a.get_type(), 'text/plain')
|
||||
eq(part2a.get_content_type(), 'text/plain')
|
||||
neq(part2a.get_payload(), 'message 2\n')
|
||||
|
||||
def test_three_lines(self):
|
||||
|
@ -2723,6 +2739,11 @@ class TestCharset(unittest.TestCase):
|
|||
c = Charset('fake')
|
||||
eq('hello w\xf6rld', c.body_encode('hello w\xf6rld'))
|
||||
|
||||
def test_unicode_charset_name(self):
|
||||
charset = Charset(u'us-ascii')
|
||||
self.assertEqual(str(charset), 'us-ascii')
|
||||
self.assertRaises(Errors.CharsetError, Charset, 'asc\xffii')
|
||||
|
||||
|
||||
|
||||
# Test multilingual MIME headers.
|
||||
|
|
|
@ -10,6 +10,13 @@ from email.Charset import Charset
|
|||
from email.Header import Header, decode_header
|
||||
from email.Message import Message
|
||||
|
||||
# We're compatible with Python 2.3, but it doesn't have the built-in Asian
|
||||
# codecs, so we have to skip all these tests.
|
||||
try:
|
||||
unicode('foo', 'euc-jp')
|
||||
except LookupError:
|
||||
raise TestSkipped
|
||||
|
||||
|
||||
|
||||
class TestEmailAsianCodecs(TestEmailBase):
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# Copyright (C) 2002-2006 Python Software Foundation
|
||||
# Contact: email-sig@python.org
|
||||
# email package unit tests for (optional) Asian codecs
|
||||
|
||||
import unittest
|
||||
from test.test_support import TestSkipped, run_unittest
|
||||
|
||||
from email.test.test_email import TestEmailBase
|
||||
from email.charset import Charset
|
||||
from email.header import Header, decode_header
|
||||
from email.message import Message
|
||||
|
||||
# We're compatible with Python 2.3, but it doesn't have the built-in Asian
|
||||
# codecs, so we have to skip all these tests.
|
||||
try:
|
||||
unicode('foo', 'euc-jp')
|
||||
except LookupError:
|
||||
raise TestSkipped
|
||||
|
||||
|
||||
|
||||
class TestEmailAsianCodecs(TestEmailBase):
|
||||
def test_japanese_codecs(self):
|
||||
eq = self.ndiffAssertEqual
|
||||
j = Charset("euc-jp")
|
||||
g = Charset("iso-8859-1")
|
||||
h = Header("Hello World!")
|
||||
jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa'
|
||||
ghello = 'Gr\xfc\xdf Gott!'
|
||||
h.append(jhello, j)
|
||||
h.append(ghello, g)
|
||||
# BAW: This used to -- and maybe should -- fold the two iso-8859-1
|
||||
# chunks into a single encoded word. However it doesn't violate the
|
||||
# standard to have them as two encoded chunks and maybe it's
|
||||
# reasonable <wink> for each .append() call to result in a separate
|
||||
# encoded word.
|
||||
eq(h.encode(), """\
|
||||
Hello World! =?iso-2022-jp?b?GyRCJU8lbSE8JW8hPCVrJUkhKhsoQg==?=
|
||||
=?iso-8859-1?q?Gr=FC=DF?= =?iso-8859-1?q?_Gott!?=""")
|
||||
eq(decode_header(h.encode()),
|
||||
[('Hello World!', None),
|
||||
('\x1b$B%O%m!<%o!<%k%I!*\x1b(B', 'iso-2022-jp'),
|
||||
('Gr\xfc\xdf Gott!', 'iso-8859-1')])
|
||||
long = 'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4\xa4\xa4\xde\xa4\xb9'
|
||||
h = Header(long, j, header_name="Subject")
|
||||
# test a very long header
|
||||
enc = h.encode()
|
||||
# TK: splitting point may differ by codec design and/or Header encoding
|
||||
eq(enc , """\
|
||||
=?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKGyhC?=
|
||||
=?iso-2022-jp?b?GyRCMnE8VCROPjVHJyRyQlQkQyRGJCQkXiQ5GyhC?=""")
|
||||
# TK: full decode comparison
|
||||
eq(h.__unicode__().encode('euc-jp'), long)
|
||||
|
||||
def test_payload_encoding(self):
|
||||
jhello = '\xa5\xcf\xa5\xed\xa1\xbc\xa5\xef\xa1\xbc\xa5\xeb\xa5\xc9\xa1\xaa'
|
||||
jcode = 'euc-jp'
|
||||
msg = Message()
|
||||
msg.set_payload(jhello, jcode)
|
||||
ustr = unicode(msg.get_payload(), msg.get_content_charset())
|
||||
self.assertEqual(jhello, ustr.encode(jcode))
|
||||
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(TestEmailAsianCodecs))
|
||||
return suite
|
||||
|
||||
|
||||
def test_main():
|
||||
run_unittest(TestEmailAsianCodecs)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,24 @@
|
|||
# Copyright (C) 2001-2004 Python Software Foundation
|
||||
# Copyright (C) 2001-2006 Python Software Foundation
|
||||
# Author: Barry Warsaw
|
||||
# Contact: email-sig@python.org
|
||||
|
||||
"""Miscellaneous utilities."""
|
||||
|
||||
__all__ = [
|
||||
'collapse_rfc2231_value',
|
||||
'decode_params',
|
||||
'decode_rfc2231',
|
||||
'encode_rfc2231',
|
||||
'formataddr',
|
||||
'formatdate',
|
||||
'getaddresses',
|
||||
'make_msgid',
|
||||
'parseaddr',
|
||||
'parsedate',
|
||||
'parsedate_tz',
|
||||
'unquote',
|
||||
]
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
@ -24,7 +39,7 @@ from email._parseaddr import parsedate_tz as _parsedate_tz
|
|||
from quopri import decodestring as _qdecode
|
||||
|
||||
# Intrapackage imports
|
||||
from email.Encoders import _bencode, _qencode
|
||||
from email.encoders import _bencode, _qencode
|
||||
|
||||
COMMASPACE = ', '
|
||||
EMPTYSTRING = ''
|
|
@ -170,7 +170,7 @@ class PyclbrTest(TestCase):
|
|||
cm('pydoc')
|
||||
|
||||
# Tests for modules inside packages
|
||||
cm('email.Parser')
|
||||
cm('email.parser')
|
||||
cm('test.test_pyclbr')
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue