69 class BadHeaderError(ValueError): |
69 class BadHeaderError(ValueError): |
70 pass |
70 pass |
71 |
71 |
72 def forbid_multi_line_headers(name, val): |
72 def forbid_multi_line_headers(name, val): |
73 """Forbids multi-line headers, to prevent header injection.""" |
73 """Forbids multi-line headers, to prevent header injection.""" |
|
74 val = force_unicode(val) |
74 if '\n' in val or '\r' in val: |
75 if '\n' in val or '\r' in val: |
75 raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name)) |
76 raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name)) |
76 try: |
77 try: |
77 val = force_unicode(val).encode('ascii') |
78 val = val.encode('ascii') |
78 except UnicodeEncodeError: |
79 except UnicodeEncodeError: |
79 if name.lower() in ('to', 'from', 'cc'): |
80 if name.lower() in ('to', 'from', 'cc'): |
80 result = [] |
81 result = [] |
81 for item in val.split(', '): |
82 for item in val.split(', '): |
82 nm, addr = parseaddr(item) |
83 nm, addr = parseaddr(item) |
83 nm = str(Header(nm, settings.DEFAULT_CHARSET)) |
84 nm = str(Header(nm, settings.DEFAULT_CHARSET)) |
84 result.append(formataddr((nm, str(addr)))) |
85 result.append(formataddr((nm, str(addr)))) |
85 val = ', '.join(result) |
86 val = ', '.join(result) |
86 else: |
87 else: |
87 val = Header(force_unicode(val), settings.DEFAULT_CHARSET) |
88 val = Header(val, settings.DEFAULT_CHARSET) |
|
89 else: |
|
90 if name.lower() == 'subject': |
|
91 val = Header(val) |
88 return name, val |
92 return name, val |
89 |
93 |
90 class SafeMIMEText(MIMEText): |
94 class SafeMIMEText(MIMEText): |
91 def __setitem__(self, name, val): |
95 def __setitem__(self, name, val): |
92 name, val = forbid_multi_line_headers(name, val) |
96 name, val = forbid_multi_line_headers(name, val) |
172 self.close() |
176 self.close() |
173 return num_sent |
177 return num_sent |
174 |
178 |
175 def _send(self, email_message): |
179 def _send(self, email_message): |
176 """A helper method that does the actual sending.""" |
180 """A helper method that does the actual sending.""" |
177 if not email_message.to: |
181 if not email_message.recipients(): |
178 return False |
182 return False |
179 try: |
183 try: |
180 self.connection.sendmail(email_message.from_email, |
184 self.connection.sendmail(email_message.from_email, |
181 email_message.recipients(), |
185 email_message.recipients(), |
182 email_message.message().as_string()) |
186 email_message.message().as_string()) |
203 All strings used to create the message can be unicode strings (or UTF-8 |
207 All strings used to create the message can be unicode strings (or UTF-8 |
204 bytestrings). The SafeMIMEText class will handle any necessary encoding |
208 bytestrings). The SafeMIMEText class will handle any necessary encoding |
205 conversions. |
209 conversions. |
206 """ |
210 """ |
207 if to: |
211 if to: |
|
212 assert not isinstance(to, basestring), '"to" argument must be a list or tuple' |
208 self.to = list(to) |
213 self.to = list(to) |
209 else: |
214 else: |
210 self.to = [] |
215 self.to = [] |
211 if bcc: |
216 if bcc: |
|
217 assert not isinstance(bcc, basestring), '"bcc" argument must be a list or tuple' |
212 self.bcc = list(bcc) |
218 self.bcc = list(bcc) |
213 else: |
219 else: |
214 self.bcc = [] |
220 self.bcc = [] |
215 self.from_email = from_email or settings.DEFAULT_FROM_EMAIL |
221 self.from_email = from_email or settings.DEFAULT_FROM_EMAIL |
216 self.subject = subject |
222 self.subject = subject |
239 else: |
245 else: |
240 msg.attach(self._create_attachment(*attachment)) |
246 msg.attach(self._create_attachment(*attachment)) |
241 msg['Subject'] = self.subject |
247 msg['Subject'] = self.subject |
242 msg['From'] = self.from_email |
248 msg['From'] = self.from_email |
243 msg['To'] = ', '.join(self.to) |
249 msg['To'] = ', '.join(self.to) |
244 msg['Date'] = formatdate() |
250 |
245 msg['Message-ID'] = make_msgid() |
251 # Email header names are case-insensitive (RFC 2045), so we have to |
|
252 # accommodate that when doing comparisons. |
|
253 header_names = [key.lower() for key in self.extra_headers] |
|
254 if 'date' not in header_names: |
|
255 msg['Date'] = formatdate() |
|
256 if 'message-id' not in header_names: |
|
257 msg['Message-ID'] = make_msgid() |
246 for name, value in self.extra_headers.items(): |
258 for name, value in self.extra_headers.items(): |
247 msg[name] = value |
259 msg[name] = value |
248 return msg |
260 return msg |
249 |
261 |
250 def recipients(self): |
262 def recipients(self): |