Esempio n. 1
0
def decodeMessageAsString(msg):
    """ This helper method takes Message object or string and returns
        string which does not contain base64 encoded parts
        Returns message without any encoding in parts
    """
    if isinstance(msg, str):
        msg = Parser().parsestr(msg)

    new = deepcopy(msg)
    # From is utf8 encoded: '=?utf-8?q?Site_Administrator_=3C=3E?='
    new.replace_header('From', decode_header(new['From'])[0][0])
    new.replace_header('Subject', decode_header(new['Subject'])[0][0])
    charset = Charset('utf-8')
    charset.header_encoding = SHORTEST
    charset.body_encoding = QP
    charset.output_charset = 'utf-8'

    for part in new.walk():
        if part.get_content_maintype() == "multipart":
            continue
        decoded = part.get_payload(decode=1)
        del part['Content-Transfer-Encoding']
        part.set_payload(decoded, charset)

    return new.as_string()
Esempio n. 2
0
def decodeMessageAsString(msg):
    """ This helper method takes Message object or string and returns
        string which does not contain base64 encoded parts
        Returns message without any encoding in parts
    """
    if isinstance(msg, str):
        msg = Parser().parsestr(msg)

    new = deepcopy(msg)
    # From is utf8 encoded: '=?utf-8?q?Site_Administrator_=3C=3E?='
    new.replace_header('From', decode_header(new['From'])[0][0])
    new.replace_header('Subject', decode_header(new['Subject'])[0][0])
    charset = Charset('utf-8')
    charset.header_encoding = SHORTEST
    charset.body_encoding = QP
    charset.output_charset = 'utf-8'

    for part in new.walk():
        if part.get_content_maintype() == "multipart":
            continue
        decoded = part.get_payload(decode=1)
        del part['Content-Transfer-Encoding']
        part.set_payload(decoded, charset)

    return new.as_string()
    def _set_charset(self, mime):
        from email.Charset import Charset, QP, BASE64, SHORTEST
        mime_encoding = self.config.get('notification', 'mime_encoding').lower()

        charset = Charset()
        charset.input_charset = 'utf-8'
        charset.output_charset = 'utf-8'
        charset.input_codec = 'utf-8'
        charset.output_codec = 'utf-8'
        if mime_encoding == 'base64':
            charset.header_encoding = BASE64
            charset.body_encoding = BASE64
        elif mime_encoding in ('qp', 'quoted-printable'):
            charset.header_encoding = QP
            charset.body_encoding = QP
        elif mime_encoding == 'none':
            charset.header_encoding = SHORTEST
            charset.body_encoding = None

        del mime['Content-Transfer-Encoding']
        mime.set_charset(charset)
Esempio n. 4
0
    def create_message(self):

        if self.attach:
            self.create_multipart_message()
        else:
            self.create_text_message()
        """comment
        """
        charset = Charset(self.encoding)
        charset.header_encoding = QP
        charset.body_encoding = QP
        self.msg.set_charset(charset)
        """
Esempio n. 5
0
    def create_message(self):

        if self.attach:
            self.create_multipart_message()
        else:
            self.create_text_message()

        """comment
        """
        charset = Charset(self.encoding)
        charset.header_encoding = QP
        charset.body_encoding = QP
        self.msg.set_charset(charset)
        """
Esempio n. 6
0
def prepare_message(template, variables, encoding="utf-8"):
    r"""Return a prepared email.Message object.

    >>> template = (u"Subject: @SUBJECT@\n"+
    ...             u"From: @FROM@\n"+
    ...             u"To: @TO@\n"+
    ...             u"BCC: @FROM@\n\n"+
    ...             u"Hello, @GREETED@!")
    >>> variables = dict(SUBJECT="Test",
    ...                  FROM="*****@*****.**",
    ...                  TO="*****@*****.**",
    ...                  GREETED="World")
    >>> message = prepare_message(template, variables)
    >>> message["SUBJECT"] == variables["SUBJECT"]
    True
    >>> message["TO"] == variables["TO"]
    True
    >>> message["FROM"] == message["BCC"] == variables["FROM"]
    True
    >>> message.get_payload()
    'Hello, World!'
    """

    template = u"\r\n".join(template.splitlines())
    template = replace_variables(template, variables)
    template = template.encode(encoding)
    message = message_from_string(template)

    DEFAULT_HEADERS = {"to": "@INVITEDEMAIL@", "from": "@INVITEREMAIL@"}
    for key, value in DEFAULT_HEADERS.iteritems():
        if key not in message:
            value = replace_variables(value, variables)
            if isinstance(value, unicode):
                value = value.encode(encoding)
            message[key] = value

    charset = Charset(encoding)
    charset.header_encoding = QP
    charset.body_encoding = QP
    message.set_charset(charset)

    for field in ("from", "to", "cc", "bcc"):
        try:
            encode_address_field(message, field, encoding, charset)
        except UnicodeEncodeError as error:
            raise InviteException("Invalid '{0}' address: {1}".format(
                field, error))

    return message
Esempio n. 7
0
def prepare_message(template, variables, encoding="utf-8"):
    r"""Return a prepared email.Message object.

    >>> template = (u"Subject: @SUBJECT@\n"+
    ...             u"From: @FROM@\n"+
    ...             u"To: @TO@\n"+
    ...             u"BCC: @FROM@\n\n"+
    ...             u"Hello, @GREETED@!")
    >>> variables = dict(SUBJECT="Test",
    ...                  FROM="*****@*****.**",
    ...                  TO="*****@*****.**",
    ...                  GREETED="World")
    >>> message = prepare_message(template, variables)
    >>> message["SUBJECT"] == variables["SUBJECT"]
    True
    >>> message["TO"] == variables["TO"]
    True
    >>> message["FROM"] == message["BCC"] == variables["FROM"]
    True
    >>> message.get_payload()
    'Hello, World!'
    """

    template = u"\r\n".join(template.splitlines())
    template = replace_variables(template, variables)
    template = template.encode(encoding)
    message = message_from_string(template)

    DEFAULT_HEADERS = {"to": "@INVITEDEMAIL@", "from": "@INVITEREMAIL@"}
    for key, value in DEFAULT_HEADERS.iteritems():
        if key not in message:
            value = replace_variables(value, variables)
            if isinstance(value, unicode):
                value = value.encode(encoding)
            message[key] = value

    charset = Charset(encoding)
    charset.header_encoding = QP
    charset.body_encoding = QP
    message.set_charset(charset)

    for field in ("from", "to", "cc", "bcc"):
        try:
            encode_address_field(message, field, encoding, charset)
        except UnicodeEncodeError as error:
            raise InviteException("Invalid '{0}' address: {1}".format(field, error))

    return message
Esempio n. 8
0
def sendmail(request, to, subject, text, mail_from=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    @param request: the request object
    @param to: recipients (list)
    @param subject: subject of email (unicode)
    @param text: email body text (unicode)
    @param mail_from: override default mail_from
    @type mail_from: unicode
    @rtype: tuple
    @return: (is_ok, Description of error or OK message)
    """
    import smtplib, socket
    from email.Message import Message
    from email.Charset import Charset, QP
    from email.Utils import formatdate, make_msgid

    _ = request.getText
    cfg = request.cfg
    mail_from = mail_from or cfg.mail_from
    subject = subject.encode(config.charset)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(config.charset)

    # Create a message using config.charset and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    msg = Message()
    charset = Charset(config.charset)
    charset.header_encoding = QP
    charset.body_encoding = QP
    msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    msg.set_payload('=')
    if msg.as_string().endswith('='):
        text = charset.body_encode(text)

    msg.set_payload(text)

    # Create message headers
    # Don't expose emails addreses of the other subscribers, instead we
    # use the same mail_from, e.g. u"Jürgen Wiki <*****@*****.**>"
    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    msg['To'] = address
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)

    if cfg.mail_sendmail:
        # Set the BCC.  This will be stripped later by sendmail.
        msg['BCC'] = ','.join(to)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug("trying to send mail (smtp) via smtp server '%s'" % cfg.mail_smarthost)
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                #server.set_debuglevel(1)
                if cfg.mail_login:
                    user, pwd = cfg.mail_login.split()
                    try: # try to do tls
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug("tls connection to smtp server established")
                    except:
                        logging.debug("could not establish a tls connection to smtp server, continuing without tls")
                    logging.debug("trying to log in to smtp server using account '%s'" % user)
                    server.login(user, pwd)
                server.sendmail(mail_from, to, msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except smtplib.SMTPException, e:
            logging.exception("smtp mail failed with an exception.")
            return (0, str(e))
        except (os.error, socket.error), e:
            logging.exception("smtp mail failed with an exception.")
            return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s") % {
                'server': cfg.mail_smarthost,
                'reason': str(e)
            })
Esempio n. 9
0
def fix_msg(msg, data):
    """
    Scan the message recursively to replace the text/html by a 
    multipart/related containing the original text/html and the new 
    clip_payload png attachment. The attachment detected and moved at
    the first pass (with Header X-Mailman-Part) will be removed.
    """

    if msg.is_multipart():
        parts = msg.get_payload()
        # remove the next level parts, then process and reattach them
        msg.set_payload(None)
        for p in parts:
            # recursive call
            r = fix_msg(p, data)
            # don't embbed related twice
            if msg.get_content_type() == 'multipart/related' and \
                 r.get_content_type() == 'multipart/related':
                for newp in r.get_payload():
                    msg.attach(newp)
            elif r == None:
                # removed
                continue
            else:
                msg.attach(r)
        # finished
        return msg
    else:
        # process the 'leaf' parts
        ctype = msg.get_content_type()
        # will be used to write back payload with correct encoding
        charset = msg.get_content_charset()
        c = Charset('utf-8')
        c.body_encoding = QP
        debug('ctype:%s charset:%s', ctype, charset)
        if ctype == 'text/plain':
            if msg['X-Mailman-Part']:
                # remove it!
                return None

            if data['do_txt']:
                # A normal txt part, add footer to plain text
                new_footer = TXT_ATTACHT_REPLACE
                new_footer += data['footer_attach']
                old_content = msg.get_payload(decode=True)
                debug('old_content:%s, new_footer:%s', \
                    type(old_content), type(new_footer))

                del msg['Content-type']
                del msg['content-transfer-encoding']
                msg.set_payload(old_content + new_footer, charset=c)

                debug('add txt footer')
                data['do_txt'] = False

            return msg
        elif ctype == 'text/html' and data['do_html']:
            # build multipart/related for HTML, will be canceled by the
            # parent recursive call if needed
            related = MIMEMultipart('related')

            html_footer = HTML_ATTACHMENT_HOLDER % \
                {'HTML_HERE': data['html_footer_attach'] }
            html_footer += '</body>'
            old_content = msg.get_payload(decode=True)
            new_content = re.sub(r'</body>', html_footer, old_content)

            if old_content != new_content:
                debug('add html footer')
            else:
                debug('no html footer added')

            del msg['content-transfer-encoding']
            msg.set_payload(new_content, charset=c)

            related.attach(msg)
            related.attach(data['clip'])
            data['do_html'] = False
            return related
        # unmodified
        return msg
Esempio n. 10
0
# NNTP message encoding trivia

from email.Header import Header
from email.Charset import Charset
from StringIO import StringIO
import email.Charset
import base64
import quopri
import re

charset = Charset('utf-8')
charset.header_encoding = email.Charset.SHORTEST
charset.body_encoding = email.Charset.SHORTEST

line_end_re = re.compile(r'\r\n|\n\r|\n(?!\r)|\r(?!\n)')

def encode_header_word(word):
    if type(word) is unicode:
        # see if it is plain ascii first
        try:
            return word.encode('us-ascii')
        except:
            # try to encode non-ascii headers using email.Header.  The
            # 1000000 value is a maximum line length, meaning never
            # fold header lines.  This is important for the XOVER
            # response.
            return str(Header(word, charset, 1000000))
    else:
        return word

# base64 encode a string, splitting lines in the output
Esempio n. 11
0
def sendmail(request, to, subject, text, mail_from=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    @param request: the request object
    @param to: recipients (list)
    @param subject: subject of email (unicode)
    @param text: email body text (unicode)
    @param mail_from: override default mail_from
    @type mail_from: unicode
    @rtype: tuple
    @return: (is_ok, Description of error or OK message)
    """
    import smtplib, socket
    from email.Message import Message
    from email.Charset import Charset, QP
    from email.Utils import formatdate, make_msgid

    _ = request.getText
    cfg = request.cfg
    mail_from = mail_from or cfg.mail_from

    logging.debug("send mail, from: %r, subj: %r" % (mail_from, subject))
    logging.debug("send mail, to: %r" % (to, ))

    if not to:
        return (1, _("No recipients, nothing to do"))

    subject = subject.encode(config.charset)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(config.charset)

    # Create a message using config.charset and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    msg = Message()
    charset = Charset(config.charset)
    charset.header_encoding = QP
    charset.body_encoding = QP
    msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    msg.set_payload('=')
    if msg.as_string().endswith('='):
        text = charset.body_encode(text)

    msg.set_payload(text)

    # Create message headers
    # Don't expose emails addreses of the other subscribers, instead we
    # use the same mail_from, e.g. u"Jürgen Wiki <*****@*****.**>"
    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    msg['To'] = address
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)
    # See RFC 3834 section 5:
    msg['Auto-Submitted'] = 'auto-generated'

    if cfg.mail_sendmail:
        # Set the BCC.  This will be stripped later by sendmail.
        msg['BCC'] = ','.join(to)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug("trying to send mail (smtp) via smtp server '%s'" %
                          cfg.mail_smarthost)
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                #server.set_debuglevel(1)
                if cfg.mail_login:
                    user, pwd = cfg.mail_login.split()
                    try:  # try to do tls
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug(
                                "tls connection to smtp server established")
                    except:
                        logging.debug(
                            "could not establish a tls connection to smtp server, continuing without tls"
                        )
                    logging.debug(
                        "trying to log in to smtp server using account '%s'" %
                        user)
                    server.login(user, pwd)
                server.sendmail(mail_from, to, msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except UnicodeError, e:
            logging.exception("unicode error [%r -> %r]" % (
                mail_from,
                to,
            ))
            return (0, str(e))
        except smtplib.SMTPException, e:
            logging.exception("smtp mail failed with an exception.")
            return (0, str(e))
Esempio n. 12
0
def sendmail(subject, text, to=None, cc=None, bcc=None, mail_from=None):
    """ Create and send a text/plain message

    Return a tuple of success or error indicator and message.

    :param subject: subject of email
    :type subject: unicode
    :param text: email body text
    :type text: unicode
    :param to: recipients
    :type to: list
    :param cc: recipients (CC)
    :type cc: list
    :param bcc: recipients (BCC)
    :type bcc: list
    :param mail_from: override default mail_from
    :type mail_from: unicode

    :rtype: tuple
    :returns: (is_ok, Description of error or OK message)
    """
    import smtplib, socket
    from email.Message import Message
    from email.Charset import Charset, QP
    from email.Utils import formatdate, make_msgid

    cfg = app.cfg
    mail_from = mail_from or cfg.mail_from

    logging.debug("send mail, from: {0!r}, subj: {1!r}".format(mail_from, subject))
    logging.debug("send mail, to: {0!r}".format(to))

    if not to and not cc and not bcc:
        return (1, _("No recipients, nothing to do"))

    subject = subject.encode(config.charset)

    # Create a text/plain body using CRLF (see RFC2822)
    text = text.replace(u'\n', u'\r\n')
    text = text.encode(config.charset)

    # Create a message using config.charset and quoted printable
    # encoding, which should be supported better by mail clients.
    # TODO: check if its really works better for major mail clients
    msg = Message()
    charset = Charset(config.charset)
    charset.header_encoding = QP
    charset.body_encoding = QP
    msg.set_charset(charset)

    # work around a bug in python 2.4.3 and above:
    msg.set_payload('=')
    if msg.as_string().endswith('='):
        text = charset.body_encode(text)

    msg.set_payload(text)

    address = encodeAddress(mail_from, charset)
    msg['From'] = address
    if to:
        msg['To'] = ','.join(to)
    if cc:
        msg['CC'] = ','.join(cc)
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid()
    msg['Subject'] = Header(subject, charset)
    # See RFC 3834 section 5:
    msg['Auto-Submitted'] = 'auto-generated'

    if cfg.mail_sendmail:
        if bcc:
            # Set the BCC.  This will be stripped later by sendmail.
            msg['BCC'] = ','.join(bcc)
        # Set Return-Path so that it isn't set (generally incorrectly) for us.
        msg['Return-Path'] = address

    # Send the message
    if not cfg.mail_sendmail:
        try:
            logging.debug("trying to send mail (smtp) via smtp server '{0}'".format(cfg.mail_smarthost))
            host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
            server = smtplib.SMTP(host, int(port))
            try:
                #server.set_debuglevel(1)
                if cfg.mail_username is not None and cfg.mail_password is not None:
                    try: # try to do tls
                        server.ehlo()
                        if server.has_extn('starttls'):
                            server.starttls()
                            server.ehlo()
                            logging.debug("tls connection to smtp server established")
                    except:
                        logging.debug("could not establish a tls connection to smtp server, continuing without tls")
                    logging.debug("trying to log in to smtp server using account '{0}'".format(cfg.mail_username))
                    server.login(cfg.mail_username, cfg.mail_password)
                server.sendmail(mail_from, (to or []) + (cc or []) + (bcc or []), msg.as_string())
            finally:
                try:
                    server.quit()
                except AttributeError:
                    # in case the connection failed, SMTP has no "sock" attribute
                    pass
        except smtplib.SMTPException as e:
            logging.exception("smtp mail failed with an exception.")
            return (0, str(e))
        except (os.error, socket.error) as e:
            logging.exception("smtp mail failed with an exception.")
            return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s",
                server=cfg.mail_smarthost,
                reason=str(e)
            ))
    else:
        try:
            logging.debug("trying to send mail (sendmail)")
            sendmailp = os.popen(cfg.mail_sendmail, "w")
            # msg contains everything we need, so this is a simple write
            sendmailp.write(msg.as_string())
            sendmail_status = sendmailp.close()
            if sendmail_status:
                logging.error("sendmail failed with status: {0!s}".format(sendmail_status))
                return (0, str(sendmail_status))
        except:
            logging.exception("sendmail failed with an exception.")
            return (0, _("Mail not sent"))

    logging.debug("Mail sent successfully")
    return (1, _("Mail sent successfully"))
Esempio n. 13
0
def process(mlist, msg, msgdata):
    # Digests and Mailman-craft messages should not get additional headers
    if msgdata.get('isdigest') or msgdata.get('nodecorate'):
        return
    d = {}
    if msgdata.get('personalize'):
        # Calculate the extra personalization dictionary.  Note that the
        # length of the recips list better be exactly 1.
        recips = msgdata.get('recips')
        assert type(recips) == ListType and len(recips) == 1
        member = recips[0].lower()
        d['user_address'] = member
        try:
            d['user_delivered_to'] = mlist.getMemberCPAddress(member)
            # BAW: Hmm, should we allow this?
            d['user_password'] = mlist.getMemberPassword(member)
            d['user_language'] = mlist.getMemberLanguage(member)
            username = mlist.getMemberName(member) or None
            try:
                username = username.encode(Utils.GetCharSet(d['user_language']))
            except (AttributeError, UnicodeError):
                username = member
            d['user_name'] = username
            d['user_optionsurl'] = mlist.GetOptionsURL(member)
        except Errors.NotAMemberError:
            pass
    # These strings are descriptive for the log file and shouldn't be i18n'd
    d.update(msgdata.get('decoration-data', {}))
    header = decorate(mlist, mlist.msg_header, 'non-digest header', d)
    footer = decorate(mlist, mlist.msg_footer, 'non-digest footer', d)
    # Escape hatch if both the footer and header are empty
    if not header and not footer:
        return
    # Be MIME smart here.  We only attach the header and footer by
    # concatenation when the message is a non-multipart of type text/plain.
    # Otherwise, if it is not a multipart, we make it a multipart, and then we
    # add the header and footer as text/plain parts.
    #
    # BJG: In addition, only add the footer if the message's character set
    # matches the charset of the list's preferred language.  This is a
    # suboptimal solution, and should be solved by allowing a list to have
    # multiple headers/footers, for each language the list supports.
    #
    # Also, if the list's preferred charset is us-ascii, we can always
    # safely add the header/footer to a plain text message since all
    # charsets Mailman supports are strict supersets of us-ascii --
    # no, UTF-16 emails are not supported yet.
    #
    # TK: Message with 'charset=' cause trouble. So, instead of
    #     mgs.get_content_charset('us-ascii') ...
    mcset = msg.get_content_charset() or 'us-ascii'
    lcset = Utils.GetCharSet(mlist.preferred_language)
    msgtype = msg.get_content_type()
    # BAW: If the charsets don't match, should we add the header and footer by
    # MIME multipart chroming the message?
    wrap = True
    if not msg.is_multipart() and msgtype == 'text/plain':
        # TK: Set up a list for Decorate charsets
        csets = []
        for cs in mm_cfg.DECORATE_CHARSETS:
            if cs == mm_cfg.DECORATE_MCSET:
                cs = mcset
            if cs == mm_cfg.DECORATE_LCSET:
                cs = lcset
            cs = Charset(cs).output_charset
            if cs not in csets:
                csets.append(cs)
        # TK: Try to keep the message plain by converting the header/
        # footer/oldpayload into unicode and encode with mcset/lcset.
        # Try to decode qp/base64 also.
        # It is possible header/footer is already unicode if it was
        # interpolated with a unicode.
        if isinstance(header, unicode):
            uheader = header
        else:
            uheader = unicode(header, lcset, 'ignore')
        if isinstance(footer, unicode):
            ufooter = footer
        else:
            ufooter = unicode(footer, lcset, 'ignore')
        try:
            oldpayload = unicode(msg.get_payload(decode=True), mcset)
            frontsep = endsep = u''
            if header and not header.endswith('\n'):
                frontsep = u'\n'
            if footer and not oldpayload.endswith('\n'):
                endsep = u'\n'
            payload = uheader + frontsep + oldpayload + endsep + ufooter
            for cs in csets:
                try:
                    newpayload = payload.encode(cs)
                    format = msg.get_param('format')
                    delsp = msg.get_param('delsp')
                    cte = msg.get('content-transfer-encoding', '').lower()
                    del msg['content-transfer-encoding']
                    del msg['content-type']
                    if mm_cfg.DECORATE_PREFER_8BIT or cs == mcset:
                        cs = Charset(cs)
                        if cte == 'quoted-printable':
                            cs.body_encoding = QP
                        elif cte == 'base64':
                            cs.body_encoding = BASE64
                        else:
                            cs.body_encoding = None
                    msg.set_payload(newpayload, cs)
                    if format:
                        msg.set_param('Format', format)
                    if delsp:
                        msg.set_param('DelSp', delsp)
                    wrap = False
                    break
                except (UnicodeError, TypeError):
                    continue
        except (LookupError, UnicodeError):
            pass
    elif msg.get_content_type() == 'multipart/mixed':
        # The next easiest thing to do is just prepend the header and append
        # the footer as additional subparts
        payload = msg.get_payload()
        if not isinstance(payload, ListType):
            payload = [payload]
        if footer:
            mimeftr = MIMEText(footer, 'plain', lcset)
            mimeftr['Content-Disposition'] = 'inline'
            payload.append(mimeftr)
        if header:
            mimehdr = MIMEText(header, 'plain', lcset)
            mimehdr['Content-Disposition'] = 'inline'
            payload.insert(0, mimehdr)
        msg.set_payload(payload)
        wrap = False
    # If we couldn't add the header or footer in a less intrusive way, we can
    # at least do it by MIME encapsulation.  We want to keep as much of the
    # outer chrome as possible.
    if not wrap:
        return
    # Because of the way Message objects are passed around to process(), we
    # need to play tricks with the outer message -- i.e. the outer one must
    # remain the same instance.  So we're going to create a clone of the outer
    # message, with all the header chrome intact, then copy the payload to it.
    # This will give us a clone of the original message, and it will form the
    # basis of the interior, wrapped Message.
    inner = Message()
    # Which headers to copy?  Let's just do the Content-* headers
    copied = False
    for h, v in msg.items():
        if h.lower().startswith('content-'):
            inner[h] = v
            copied = True
    inner.set_payload(msg.get_payload())
    # For completeness
    inner.set_unixfrom(msg.get_unixfrom())
    inner.preamble = msg.preamble
    inner.epilogue = msg.epilogue
    # Don't copy get_charset, as this might be None, even if
    # get_content_charset isn't.  However, do make sure there is a default
    # content-type, even if the original message was not MIME.
    inner.set_default_type(msg.get_default_type())
    if not copied:
        inner['Content-Type'] = inner.get_content_type()
    if msg['mime-version'] == None:
        msg['MIME-Version'] = '1.0'
    # BAW: HACK ALERT.
    if hasattr(msg, '__version__'):
        inner.__version__ = msg.__version__
    # Now, play games with the outer message to make it contain three
    # subparts: the header (if any), the wrapped message, and the footer (if
    # any).
    payload = [inner]
    if header:
        mimehdr = MIMEText(header, 'plain', lcset)
        mimehdr['Content-Disposition'] = 'inline'
        payload.insert(0, mimehdr)
    if footer:
        mimeftr = MIMEText(footer, 'plain', lcset)
        mimeftr['Content-Disposition'] = 'inline'
        payload.append(mimeftr)
    msg.set_payload(payload)
    del msg['content-type']
    del msg['content-transfer-encoding']
    del msg['content-disposition']
    msg['Content-Type'] = 'multipart/mixed'