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
|
---|