| 1 | Index: django/core/mail.py
|
|---|
| 2 | ===================================================================
|
|---|
| 3 | --- django/core/mail.py Tue Jun 26 14:46:08 2007
|
|---|
| 4 | +++ django/core/mail.py Tue Jun 26 14:48:15 2007
|
|---|
| 5 | @@ -4,6 +4,10 @@
|
|---|
| 6 |
|
|---|
| 7 | from django.conf import settings
|
|---|
| 8 | from email.MIMEText import MIMEText
|
|---|
| 9 | +from email.MIMEMultipart import MIMEMultipart
|
|---|
| 10 | +from email.MIMEBase import MIMEBase
|
|---|
| 11 | +from email import Encoders
|
|---|
| 12 | +import mimetypes
|
|---|
| 13 | from email.Header import Header
|
|---|
| 14 | from email.Utils import formatdate
|
|---|
| 15 | from email import Charset
|
|---|
| 16 | @@ -13,6 +17,9 @@
|
|---|
| 17 | import time
|
|---|
| 18 | import random
|
|---|
| 19 |
|
|---|
| 20 | +# Default MIME type to use for attachments if it cannot be guessed.
|
|---|
| 21 | +DEFAULT_ATTACHMENT_MIME_TYPE = 'application/octet-stream'
|
|---|
| 22 | +
|
|---|
| 23 | # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from
|
|---|
| 24 | # some spam filters.
|
|---|
| 25 | Charset.add_charset('utf-8', Charset.SHORTEST, Charset.QP, 'utf-8')
|
|---|
| 26 | @@ -64,6 +71,15 @@
|
|---|
| 27 | val = Header(val, settings.DEFAULT_CHARSET)
|
|---|
| 28 | MIMEText.__setitem__(self, name, val)
|
|---|
| 29 |
|
|---|
| 30 | +class SafeMIMEMultipart(MIMEMultipart):
|
|---|
| 31 | + def __setitem__(self, name, val):
|
|---|
| 32 | + "Forbids multi-line headers, to prevent header injection."
|
|---|
| 33 | + if '\n' in val or '\r' in val:
|
|---|
| 34 | + raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
|---|
| 35 | + if name == 'Subject':
|
|---|
| 36 | + val = Header(val, settings.DEFAULT_CHARSET)
|
|---|
| 37 | + MIMEMultipart.__setitem__(self, name, val)
|
|---|
| 38 | +
|
|---|
| 39 | class SMTPConnection(object):
|
|---|
| 40 | """
|
|---|
| 41 | A wrapper that manages the SMTP network connection.
|
|---|
| 42 | @@ -161,6 +177,7 @@
|
|---|
| 43 | self.subject = subject
|
|---|
| 44 | self.body = body
|
|---|
| 45 | self.connection = connection
|
|---|
| 46 | + self.attachments = []
|
|---|
| 47 |
|
|---|
| 48 | def get_connection(self, fail_silently=False):
|
|---|
| 49 | if not self.connection:
|
|---|
| 50 | @@ -169,6 +186,12 @@
|
|---|
| 51 |
|
|---|
| 52 | def message(self):
|
|---|
| 53 | msg = SafeMIMEText(self.body, 'plain', settings.DEFAULT_CHARSET)
|
|---|
| 54 | + if self.attachments:
|
|---|
| 55 | + body_msg = msg
|
|---|
| 56 | + msg = SafeMIMEMultipart()
|
|---|
| 57 | + msg.attach(body_msg)
|
|---|
| 58 | + for params in self.attachments:
|
|---|
| 59 | + msg.attach(self._compile_attachment(*params))
|
|---|
| 60 | msg['Subject'] = self.subject
|
|---|
| 61 | msg['From'] = self.from_email
|
|---|
| 62 | msg['To'] = ', '.join(self.to)
|
|---|
| 63 | @@ -189,6 +212,39 @@
|
|---|
| 64 | """Send the email message."""
|
|---|
| 65 | return self.get_connection(fail_silently).send_messages([self])
|
|---|
| 66 |
|
|---|
| 67 | + def attach(self, filename, content, mimetype=None):
|
|---|
| 68 | + """Attaches a file with the given filename and content."""
|
|---|
| 69 | + self.attachments.append((filename, content, mimetype))
|
|---|
| 70 | +
|
|---|
| 71 | + def attach_file(self, path, mimetype=None):
|
|---|
| 72 | + """Attaches a file from the filesystem."""
|
|---|
| 73 | + filename = os.path.basename(path)
|
|---|
| 74 | + f = open(path, 'rb')
|
|---|
| 75 | + content = f.read()
|
|---|
| 76 | + f.close()
|
|---|
| 77 | + self.attach(filename, content, mimetype)
|
|---|
| 78 | +
|
|---|
| 79 | + def _compile_attachment(self, filename, content, mimetype):
|
|---|
| 80 | + """
|
|---|
| 81 | + Compiles the given attachment to a MIME object and returns the new
|
|---|
| 82 | + attachment.
|
|---|
| 83 | + """
|
|---|
| 84 | + if mimetype is None:
|
|---|
| 85 | + # Guess the mimetype based on the filename if possible.
|
|---|
| 86 | + mimetype, xx = mimetypes.guess_type(filename)
|
|---|
| 87 | + if mimetype is None:
|
|---|
| 88 | + mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
|
|---|
| 89 | + basetype, subtype = mimetype.split('/', 1)
|
|---|
| 90 | + if basetype == 'text':
|
|---|
| 91 | + attachment = SafeMIMEText(content, subtype, settings.DEFAULT_CHARSET)
|
|---|
| 92 | + else:
|
|---|
| 93 | + # Encode non-text attachments with base64.
|
|---|
| 94 | + attachment = MIMEBase(basetype, subtype)
|
|---|
| 95 | + attachment.set_payload(content)
|
|---|
| 96 | + Encoders.encode_base64(attachment)
|
|---|
| 97 | + attachment.add_header('Content-Disposition', 'attachment', filename=filename)
|
|---|
| 98 | + return attachment
|
|---|
| 99 | +
|
|---|
| 100 |
|
|---|
| 101 | Index: docs/email.txt
|
|---|
| 102 | ===================================================================
|
|---|
| 103 | --- docs/email.txt Mon Jun 25 09:36:30 2007
|
|---|
| 104 | +++ docs/email.txt Tue Jun 26 14:33:28 2007
|
|---|
| 105 | @@ -198,8 +198,8 @@
|
|---|
| 106 | .. note::
|
|---|
| 107 | Not all features of the ``EmailMessage`` class are available through the
|
|---|
| 108 | ``send_mail()`` and related wrapper functions. If you wish to use advanced
|
|---|
| 109 | - features, such as BCC'ed recipients or multi-part e-mail, you'll need to
|
|---|
| 110 | - create ``EmailMessage`` instances directly.
|
|---|
| 111 | + features, such as BCC'ed recipients, file attachments, or multi-part
|
|---|
| 112 | + e-mail, you'll need to create ``EmailMessage`` instances directly.
|
|---|
| 113 |
|
|---|
| 114 | In general, ``EmailMessage`` is responsible for creating the e-mail message
|
|---|
| 115 | itself. ``SMTPConnection`` is responsible for the network connection side of
|
|---|
| 116 | @@ -238,6 +238,20 @@
|
|---|
| 117 | SMTP server needs to be told the full list of recipients when the message
|
|---|
| 118 | is sent. If you add another way to specify recipients in your class, they
|
|---|
| 119 | need to be returned from this method as well.
|
|---|
| 120 | +
|
|---|
| 121 | + * ``attach()`` creates a new file attachment and adds it to the message. It
|
|---|
| 122 | + takes three arguments: ``filename``, ``content`` and ``mimetype``.
|
|---|
| 123 | + ``filename`` is the name of the file attachment as it will appear in the
|
|---|
| 124 | + email. ``content`` is the data that will be contained inside the
|
|---|
| 125 | + attachment. ``mimetype`` is optional, and defines the attachment's MIME
|
|---|
| 126 | + content type. If you omit ``mimetype``, the MIME content type will be
|
|---|
| 127 | + guessed from the filename of the attachment.
|
|---|
| 128 | +
|
|---|
| 129 | + * ``attach_file()`` creates a new attachment using a file on the
|
|---|
| 130 | + filesystem, and takes two arguments. The first is the path of the file to
|
|---|
| 131 | + attach. The second argument is the MIME content type to use for the
|
|---|
| 132 | + attachment, and is optional. If the MIME type is omitted then it will be
|
|---|
| 133 | + guessed from the filename.
|
|---|
| 134 |
|
|---|
| 135 | The ``SMTPConnection`` class is initialized with the host, port, username and
|
|---|
| 136 | password for the SMTP server. If you don't specify one or more of those
|
|---|