Commit bb5874d5 by Adam

truncate email from addresses if >320 chars when encoded (TNL-4264) (#12171)

* truncate email from addresses if >320 chars when encoded (TNL-4264)

* use exact lengths
parent 85453fb0
...@@ -32,6 +32,7 @@ from celery.exceptions import RetryTaskError # pylint: disable=no-name-in-modul ...@@ -32,6 +32,7 @@ from celery.exceptions import RetryTaskError # pylint: disable=no-name-in-modul
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.mail import EmailMultiAlternatives, get_connection from django.core.mail import EmailMultiAlternatives, get_connection
from django.core.mail.message import forbid_multi_line_headers
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from bulk_email.models import ( from bulk_email.models import (
...@@ -384,13 +385,20 @@ def _filter_optouts_from_recipients(to_list, course_id): ...@@ -384,13 +385,20 @@ def _filter_optouts_from_recipients(to_list, course_id):
return to_list, num_optout return to_list, num_optout
def _get_source_address(course_id, course_title): def _get_source_address(course_id, course_title, truncate=True):
""" """
Calculates an email address to be used as the 'from-address' for sent emails. Calculates an email address to be used as the 'from-address' for sent emails.
Makes a unique from name and address for each course, e.g. Makes a unique from name and address for each course, e.g.
"COURSE_TITLE" Course Staff <coursenum-no-reply@courseupdates.edx.org> "COURSE_TITLE" Course Staff <course_name-no-reply@courseupdates.edx.org>
If, when decoded to ascii, this from_addr is longer than 320 characters,
use the course_name rather than the course title, e.g.
"course_name" Course Staff <course_name-no-reply@courseupdates.edx.org>
The "truncate" kwarg is only used for tests.
""" """
course_title_no_quotes = re.sub(r'"', '', course_title) course_title_no_quotes = re.sub(r'"', '', course_title)
...@@ -418,10 +426,11 @@ def _get_source_address(course_id, course_title): ...@@ -418,10 +426,11 @@ def _get_source_address(course_id, course_title):
from_addr = format_address(course_title_no_quotes) from_addr = format_address(course_title_no_quotes)
# If it's longer than 320 characters, reformat, but with the course name # If the encoded from_addr is longer than 320 characters, reformat,
# rather than course title. Amazon SES's from address field appears to have a maximum # but with the course name rather than course title.
# length of 320. # Amazon SES's from address field appears to have a maximum length of 320.
if len(from_addr) >= 320: __, encoded_from_addr = forbid_multi_line_headers('from', from_addr, 'utf-8')
if len(encoded_from_addr) >= 320 and truncate:
from_addr = format_address(course_name) from_addr = format_address(course_name)
return from_addr return from_addr
......
...@@ -10,11 +10,13 @@ from unittest import skipIf ...@@ -10,11 +10,13 @@ from unittest import skipIf
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.core.mail.message import forbid_multi_line_headers
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.management import call_command from django.core.management import call_command
from django.test.utils import override_settings from django.test.utils import override_settings
from bulk_email.models import Optout from bulk_email.models import Optout
from bulk_email.tasks import _get_source_address
from courseware.tests.factories import StaffFactory, InstructorFactory from courseware.tests.factories import StaffFactory, InstructorFactory
from instructor_task.subtasks import update_subtask_status from instructor_task.subtasks import update_subtask_status
from student.roles import CourseStaffRole from student.roles import CourseStaffRole
...@@ -322,13 +324,24 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase) ...@@ -322,13 +324,24 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
'message': 'test message for self' 'message': 'test message for self'
} }
# make very long display_name for course # make display_name that's longer than 320 characters when encoded
long_name = u"x" * 321 # to ascii, but shorter than 320 unicode characters
long_name = u"é" * 200
course = CourseFactory.create( course = CourseFactory.create(
display_name=long_name, number="bulk_email_course_name" display_name=long_name, number="bulk_email_course_name"
) )
instructor = InstructorFactory(course_key=course.id) instructor = InstructorFactory(course_key=course.id)
unexpected_from_addr = _get_source_address(
course.id, course.display_name, truncate=False
)
__, encoded_unexpected_from_addr = forbid_multi_line_headers(
"from", unexpected_from_addr, 'utf-8'
)
self.assertEqual(len(encoded_unexpected_from_addr), 748)
self.assertEqual(len(unexpected_from_addr), 261)
self.login_as_user(instructor) self.login_as_user(instructor)
send_mail_url = reverse('send_email', kwargs={'course_id': unicode(course.id)}) send_mail_url = reverse('send_email', kwargs={'course_id': unicode(course.id)})
response = self.client.post(send_mail_url, test_email) response = self.client.post(send_mail_url, test_email)
...@@ -337,11 +350,13 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase) ...@@ -337,11 +350,13 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
from_email = mail.outbox[0].from_email from_email = mail.outbox[0].from_email
expected_from_addr = (
u'"{course_name}" Course Staff <{course_name}-no-reply@example.com>'
).format(course_name=course.id.course)
self.assertEqual( self.assertEqual(
from_email, from_email,
u'"{course_name}" Course Staff <{course_name}-no-reply@example.com>'.format( expected_from_addr
course_name=course.id.course
)
) )
self.assertEqual(len(from_email), 83) self.assertEqual(len(from_email), 83)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment