diff --git a/Lib/email/message.py b/Lib/email/message.py --- a/Lib/email/message.py +++ b/Lib/email/message.py @@ -109,16 +109,39 @@ class Message: self._unixfrom = None self._payload = None self._charset = None # Defaults for multipart messages self.preamble = self.epilogue = None self.defects = [] # Default content type self._default_type = 'text/plain' + # this is a naive backport of _default_header_map + # in Lib/email/headerregistry.py + self._unique_headers = { + # header name, count + 'subject': 1, + 'date': 1, + 'resent-date': 0, + 'orig-date': 1, + 'sender': 1, + 'resent-sender': 1, + 'to': 1, + 'resent-to': 0, + 'cc': 1, + 'resent-cc': 0, + 'bcc': 1, + 'resent-bcc': 0, + 'from': 1, + 'resent-from': 0, + 'reply-to': 1, + 'mime-version': 1, + 'content-disposition': 1, + 'content-transfer-encoding': 1, + } def __str__(self): """Return the entire formatted message as a string. This includes the headers, body, and envelope header. """ return self.as_string(unixfrom=True) def as_string(self, unixfrom=False): @@ -294,16 +317,26 @@ class Message: return self.get(name) def __setitem__(self, name, val): """Set the value of a header. Note: this does not overwrite an existing header with the same field name. Use __delitem__() first to delete any existing headers. """ + lname = name.lower() + max_count = self._unique_headers.get(lname) + if max_count: + found = 0 + for k, v in self._headers: + if k.lower() == lname: + found += 1 + if found>= max_count: + raise ValueError("There may be at most {} {} headers " + "in a message".format(max_count, name)) self._headers.append((name, val)) def __delitem__(self, name): """Delete all occurrences of a header, if present. Does not raise an exception if the header is missing. """ name = name.lower() diff --git a/Lib/email/test/data/msg_25.txt b/Lib/email/test/data/msg_25.txt --- a/Lib/email/test/data/msg_25.txt +++ b/Lib/email/test/data/msg_25.txt @@ -4,17 +4,16 @@ Received: from [204.245.199.98] (helo=zi id 14lYR6-0008Iv-00 for linuxuser-admin@www.linux.org.uk; 2001年4月06日 16:46:09 +0100 Received: from localhost (localhost) by zinfandel.lacita.com (8.7.3/8.6.10-MT4.00) with internal id JAB03225; Fri, 6 Apr 2001 09:23:06 -0800 (GMT-0800) Date: Fri, 6 Apr 2001 09:23:06 -0800 (GMT-0800) From: Mail Delivery Subsystem Subject: Returned mail: Too many hops 19 (17 max): from via [199.164.235.226], to Message-Id: <200104061723.jab03225@zinfandel.lacita.com> To: -To: postmaster@zinfandel.lacita.com MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; bo Auto-Submitted: auto-generated (failure) This is a MIME-encapsulated message --JAB03225.986577786/zinfandel.lacita.com diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -1068,16 +1068,31 @@ class TestMIMEImage(unittest.TestCase): # Test the basic MIMEText class class TestMIMEText(unittest.TestCase): def setUp(self): self._msg = MIMEText('hello there') + def test_duplicate_headers(self): + tests = [ + # header, value + ('Subject', 'this is a subject'), + ('To', 'mr@biggless.com'), + ('Cc', 'cc@biggless.com'), + ('Bcc', 'bcc@biggless.com'), + ('From', 'from@biggless.com'), + ] + for header, value in tests: + m = MIMEText('test for %r header' % header) + m[header] = value + with self.assertRaises(ValueError): + m[header] = value + def test_types(self): eq = self.assertEqual eq(self._msg.get_content_type(), 'text/plain') eq(self._msg.get_param('charset'), 'us-ascii') missing = [] self.assertIs(self._msg.get_param('foobar', missing), missing) self.assertIs(self._msg.get_param('charset', missing, header='foobar'), missing)

AltStyle によって変換されたページ (->オリジナル) /