| 1 | from email.iterators import _structure
|
|---|
| 2 | from email.message import Message
|
|---|
| 3 | from email.mime.image import MIMEImage
|
|---|
| 4 | from email.mime.multipart import MIMEMultipart
|
|---|
| 5 | from email.mime.text import MIMEText
|
|---|
| 6 |
|
|---|
| 7 | from django.core.mail import EmailMultiAlternatives
|
|---|
| 8 | from django.test import SimpleTestCase
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 | class RelatedPartTests(SimpleTestCase):
|
|---|
| 12 | def dump_message(self, message: Message) -> None:
|
|---|
| 13 | print(f"\n\n##### {self._testMethodName} #####")
|
|---|
| 14 | _structure(message) # Dumps outline of message parts to stdout.
|
|---|
| 15 | print()
|
|---|
| 16 | # Uncomment to also dump the raw MIME message:
|
|---|
| 17 | # print(message.as_bytes().decode())
|
|---|
| 18 | # print()
|
|---|
| 19 |
|
|---|
| 20 | def setUp(self):
|
|---|
| 21 | self.email = EmailMultiAlternatives(body="Plain text body")
|
|---|
| 22 |
|
|---|
| 23 | self.image = MIMEImage(b"GIF89a...", "gif")
|
|---|
| 24 | self.image["Content-Disposition"] = "inline"
|
|---|
| 25 | self.image["Content-ID"] = "<image>"
|
|---|
| 26 |
|
|---|
| 27 | self.related = MIMEMultipart("related")
|
|---|
| 28 | self.related.attach(MIMEText("HTML body", "html"))
|
|---|
| 29 | self.related.attach(self.image)
|
|---|
| 30 |
|
|---|
| 31 | def test_raw_python_message(self):
|
|---|
| 32 | # No Django EmailMultiAlternative helpers. This achieves the goal:
|
|---|
| 33 | # multipart/alternative
|
|---|
| 34 | # text/plain
|
|---|
| 35 | # multipart/related
|
|---|
| 36 | # text/html
|
|---|
| 37 | # image/gif: Content-Disposition: inline; Content-ID: <image>
|
|---|
| 38 | message = Message() # Python Message (not Django EmailMessage)
|
|---|
| 39 | message["Content-Type"] = "multipart/alternative"
|
|---|
| 40 | message.attach(MIMEText("Plain text body", "plain"))
|
|---|
| 41 | message.attach(self.related)
|
|---|
| 42 | self.dump_message(message)
|
|---|
| 43 |
|
|---|
| 44 | def test_attach_alternative(self):
|
|---|
| 45 | # TypeError: expected bytes-like object, not MIMEMultipart
|
|---|
| 46 | # in EmailMessage._create_alternatives ... _create_mime_attachment.
|
|---|
| 47 | self.email.attach_alternative(self.related, "multipart/related")
|
|---|
| 48 | message = self.email.message() # TypeError
|
|---|
| 49 | self.dump_message(message)
|
|---|
| 50 |
|
|---|
| 51 | def test_attach_alternative_serialized(self):
|
|---|
| 52 | # multipart/alternative
|
|---|
| 53 | # text/plain
|
|---|
| 54 | # multipart/related: entire part, base64 encoded
|
|---|
| 55 | self.email.attach_alternative(self.related.as_bytes(), "multipart/related")
|
|---|
| 56 | message = self.email.message()
|
|---|
| 57 | self.dump_message(message)
|
|---|
| 58 |
|
|---|
| 59 | def test_attach_alternative_serialized_text(self):
|
|---|
| 60 | # multipart/alternative
|
|---|
| 61 | # text/plain
|
|---|
| 62 | # multipart/related: entire part, base64 encoded
|
|---|
| 63 | self.email.attach_alternative(self.related.as_bytes().decode(), "multipart/related")
|
|---|
| 64 | message = self.email.message()
|
|---|
| 65 | self.dump_message(message)
|
|---|
| 66 |
|
|---|
| 67 | def test_attach(self):
|
|---|
| 68 | # TypeError: expected bytes-like object, not MIMEMultipart
|
|---|
| 69 | # in EmailMessage._create_attachments ... _create_mime_attachment.
|
|---|
| 70 | self.email.attach("", self.related, "multipart/related")
|
|---|
| 71 | message = self.email.message() # TypeError
|
|---|
| 72 | self.dump_message(message)
|
|---|
| 73 |
|
|---|
| 74 | def test_attach_serialized(self):
|
|---|
| 75 | # multipart/mixed
|
|---|
| 76 | # text/plain
|
|---|
| 77 | # multipart/related: entire part, base64 encoded
|
|---|
| 78 | self.email.attach("", self.related.as_bytes(), "multipart/related")
|
|---|
| 79 | message = self.email.message()
|
|---|
| 80 | self.dump_message(message)
|
|---|
| 81 |
|
|---|
| 82 | def test_attach_serialized_text(self):
|
|---|
| 83 | # multipart/mixed
|
|---|
| 84 | # text/plain
|
|---|
| 85 | # multipart/related: entire part, base64 encoded
|
|---|
| 86 | self.email.attach("", self.related.as_bytes().decode(), "multipart/related")
|
|---|
| 87 | message = self.email.message()
|
|---|
| 88 | self.dump_message(message)
|
|---|
| 89 |
|
|---|
| 90 | def test_attach_inline_image_directly(self):
|
|---|
| 91 | # This is not technically accurate (the inline image should be in a
|
|---|
| 92 | # related part with its html content), but most email clients will
|
|---|
| 93 | # render the inline image in the html as desired:
|
|---|
| 94 | #
|
|---|
| 95 | # multipart/mixed
|
|---|
| 96 | # multipart/alternative
|
|---|
| 97 | # text/plain
|
|---|
| 98 | # text/html
|
|---|
| 99 | # image/gif: Content-Disposition: inline; Content-ID: <image>
|
|---|
| 100 | self.email.attach_alternative("HTML body", "text/html")
|
|---|
| 101 | self.email.attach(self.image)
|
|---|
| 102 | message = self.email.message()
|
|---|
| 103 | self.dump_message(message)
|
|---|