Skip to content
Browse files

Fixed #1135 -- Changed django.core.mail functions not to allow newlin…

…es in headers

git-svn-id: bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent f7f812c commit 8b5c2192e8698f777102cf56bdbed2170df09cc0 @adrianholovaty adrianholovaty committed
Showing with 46 additions and 1 deletion.
  1. +8 −1 django/core/
  2. +38 −0 docs/email.txt
9 django/core/
@@ -4,6 +4,13 @@
from email.MIMEText import MIMEText
import smtplib
+class SafeMIMEText(MIMEText):
+ def __setitem__(self, name, val):
+ "Forbids multi-line headers, to prevent header injection."
+ if '\n' in val or '\r' in val:
+ raise ValueError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
+ MIMEText.__setitem__(self, name, val)
def send_mail(subject, message, from_email, recipient_list, fail_silently=False):
Easy wrapper for sending a single message to a recipient list. All members
@@ -29,7 +36,7 @@ def send_mass_mail(datatuple, fail_silently=False):
if not recipient_list:
from_email = from_email or DEFAULT_FROM_EMAIL
- msg = MIMEText(message)
+ msg = SafeMIMEText(message)
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ', '.join(recipient_list)
38 docs/email.txt
@@ -114,3 +114,41 @@ receiving a separate e-mail::
('Subject', 'Message.', '', [''],
+Preventing header injection
+**New in Django development version.**
+`Header injection`_ is a security exploit in which an attacker inserts extra
+e-mail headers to control the "To:" and "From:" in e-mail messages that your
+scripts generate.
+The Django e-mail functions outlined above all protect against header injection
+by forbidding newlines in header values. If any ``subject``, ``from_email`` or
+``recipient_list`` contains a newline, the e-mail function (e.g.
+``send_mail()``) will raise ``ValueError`` and, hence, will not send the
+e-mail. It's your responsibility to validate all data before passing it to the
+e-mail functions.
+Here's an example view that takes a ``subject``, ``message`` and ``from_email``
+from the request's POST data, sends that to and redirects to
+"/contact/thanks/" when it's done::
+ from django.core.mail import send_mail
+ def send_email(request):
+ subject = request.POST.get('subject', '')
+ message = request.POST.get('message', '')
+ from_email = request.POST.get('from_email', '')
+ if subject and message and from_email \
+ and '\n' not in subject and '\n' not in message
+ and '\n' not in from_email:
+ send_mail(subject, message, from_email, [''])
+ return HttpResponseRedirect('/contact/thanks/')
+ else:
+ # In reality we'd use a manipulator
+ # to get proper validation errors.
+ return HttpResponse('Make sure all fields are entered and valid.')
+.. _Header injection:

0 comments on commit 8b5c219

Please sign in to comment.
Something went wrong with that request. Please try again.