Ticket #6918: mail-header-encoding.diff

File mail-header-encoding.diff, 6.8 KB (added by serialx, 7 years ago)

New improved working patch. (It actually changes the encoding of the mail header)

  • django/core/mail.py

    old new  
    6969class BadHeaderError(ValueError):
    7070    pass
    7171
    72 def forbid_multi_line_headers(name, val):
     72def forbid_multi_line_headers(name, val, header_encoding):
    7373    """Forbids multi-line headers, to prevent header injection."""
    7474    if '\n' in val or '\r' in val:
    7575        raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
     
    8080            result = []
    8181            for item in val.split(', '):
    8282                nm, addr = parseaddr(item)
    83                 nm = str(Header(nm, settings.DEFAULT_CHARSET))
     83                nm = str(Header(nm, header_encoding))
    8484                result.append(formataddr((nm, str(addr))))
    8585            val = ', '.join(result)
    8686        else:
    87             val = Header(force_unicode(val), settings.DEFAULT_CHARSET)
     87            val = Header(force_unicode(val), header_encoding)
    8888    return name, val
    8989
    9090class SafeMIMEText(MIMEText):
     91    def __init__(self, text, subtype, charset, header_encoding=None):
     92        self.header_encoding = header_encoding or settings.DEFAULT_CHARSET
     93        MIMEText.__init__(self, text, subtype, charset)
    9194    def __setitem__(self, name, val):
    92         name, val = forbid_multi_line_headers(name, val)
     95        name, val = forbid_multi_line_headers(name, val, self.header_encoding)
    9396        MIMEText.__setitem__(self, name, val)
    9497
    9598class SafeMIMEMultipart(MIMEMultipart):
     99    def __init__(self, _subtype='mixed', boundary=None, _subparts=None, header_encoding=None, **_params):
     100        self.header_encoding = header_encoding or settings.DEFAULT_CHARSET
     101        MIMEMultipart.__init__(self, _subtype, boundary, _subparts, **_params)
    96102    def __setitem__(self, name, val):
    97         name, val = forbid_multi_line_headers(name, val)
     103        name, val = forbid_multi_line_headers(name, val, self.header_encoding)
    98104        MIMEMultipart.__setitem__(self, name, val)
    99105
    100106class SMTPConnection(object):
     
    195201    encoding = None     # None => use settings default
    196202
    197203    def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
    198             connection=None, attachments=None, headers=None):
     204            connection=None, attachments=None, headers=None, header_encoding=None):
    199205        """
    200206        Initialize a single email message (which can be sent to multiple
    201207        recipients).
     
    220226        self.attachments = attachments or []
    221227        self.extra_headers = headers or {}
    222228        self.connection = connection
     229        self.header_encoding = header_encoding
    223230
    224231    def get_connection(self, fail_silently=False):
    225232        if not self.connection:
     
    228235
    229236    def message(self):
    230237        encoding = self.encoding or settings.DEFAULT_CHARSET
     238        header_encoding = self.header_encoding or settings.DEFAULT_CHARSET
    231239        msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET),
    232                            self.content_subtype, encoding)
     240                           self.content_subtype, encoding, header_encoding)
    233241        if self.attachments:
    234242            body_msg = msg
    235             msg = SafeMIMEMultipart(_subtype=self.multipart_subtype)
     243            msg = SafeMIMEMultipart(_subtype=self.multipart_subtype, header_encoding=header_encoding)
    236244            if self.body:
    237245                msg.attach(body_msg)
    238246            for attachment in self.attachments:
     
    318326        self.attach(content=content, mimetype=mimetype)
    319327
    320328def send_mail(subject, message, from_email, recipient_list,
    321               fail_silently=False, auth_user=None, auth_password=None):
     329              fail_silently=False, auth_user=None, auth_password=None,
     330              header_encoding=None):
    322331    """
    323332    Easy wrapper for sending a single message to a recipient list. All members
    324333    of the recipient list will see the other recipients in the 'To' field.
    325334
    326335    If auth_user is None, the EMAIL_HOST_USER setting is used.
    327336    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
     337    If header_encoding is None, the DEFAULT_CHARSET setting is used.
    328338
    329339    Note: The API for this method is frozen. New code wanting to extend the
    330340    functionality should use the EmailMessage class directly.
     
    332342    connection = SMTPConnection(username=auth_user, password=auth_password,
    333343                                fail_silently=fail_silently)
    334344    return EmailMessage(subject, message, from_email, recipient_list,
    335                         connection=connection).send()
     345                        connection=connection, header_encoding=header_encoding).send()
    336346
    337347def send_mass_mail(datatuple, fail_silently=False, auth_user=None,
    338                    auth_password=None):
     348                   auth_password=None, header_encoding=None):
    339349    """
    340350    Given a datatuple of (subject, message, from_email, recipient_list), sends
    341351    each message to each recipient list. Returns the number of e-mails sent.
     
    344354    If auth_user and auth_password are set, they're used to log in.
    345355    If auth_user is None, the EMAIL_HOST_USER setting is used.
    346356    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
     357    If header_encoding is None, the DEFAULT_CHARSET setting is used.
    347358
    348359    Note: The API for this method is frozen. New code wanting to extend the
    349360    functionality should use the EmailMessage class directly.
    350361    """
    351362    connection = SMTPConnection(username=auth_user, password=auth_password,
    352363                                fail_silently=fail_silently)
    353     messages = [EmailMessage(subject, message, sender, recipient)
     364    messages = [EmailMessage(subject, message, sender, recipient, header_encoding=header_encoding)
    354365                for subject, message, sender, recipient in datatuple]
    355366    return connection.send_messages(messages)
    356367
  • docs/email.txt

    old new  
    245245      caller to ensure header names and values are in the correct format for
    246246      an e-mail message.
    247247
     248    * ``header_encoding``: The encoding of the email header. Defaults to DEFAULT_CHARSET
     249      setting.
     250
    248251For example::
    249252
    250253    email = EmailMessage('Hello', 'Body goes here', 'from@example.com',
    251254                ['to1@example.com', 'to2@example.com'], ['bcc@example.com'],
    252                 headers = {'Reply-To': 'another@example.com'})
     255                headers = {'Reply-To': 'another@example.com'},
     256                header_encoding = 'utf-8')
    253257
    254258The class has the following methods:
    255259
Back to Top