def download_email(request, inbox=None, domain=None, email=None): if single_email_ratelimit.counter_full(request): raise Http404 try: email = models.Email.objects.viewable(request.user).filter( inbox__inbox=inbox, inbox__domain__domain=domain, ).select_related("inbox", "inbox__domain").get(id=int(email, 16)) except models.Email.DoesNotExist: raise Http404 single_email_ratelimit.counter_increase(request) msg = make_message(email) # set unixfrom to True to turn a single message into a valid mbox data = msg.as_bytes(unixfrom=True) response = HttpResponse( content=data, status=200, ) response["Content-Length"] = len(data) response["Content-Disposition"] = "attachment; filename={}-{}.mbox".format( str(email.inbox), email) response[ "Content-Type"] = "application/mbox" # a single email is the same as a mbox return response
def test_alterative(self): msg = mail.MailRequest("", "", "", EXAMPLE_ALT) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_alterative(self): msg = mail.MailRequest("", "", "", EXAMPLE_ALT) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_encoders_used(self): # make message with base64 part, uuencode part, 8bit part, 7bit part, # quopri part, and some invalid part body_data = b"Hello\n\nHow are you?\n" email = factories.EmailFactory(inbox=self.inbox) body = factories.BodyFactory(data=body_data) first_part = factories.PartListFactory( email=email, body=factories.BodyFactory(data=b"")) factories.HeaderFactory( part=first_part, name="Content-Type", data="multipart/mixed; boundary=\"=-3BRZDE/skgKPPh+RuFa/\"") encodings = { "base64": check_base64, "quoted-printable": check_quopri, "uuencode": check_uu, "x-uuencode": check_uu, "uue": check_uu, "x-uue": check_uu, "7-bit": check_noop, "8-bit": check_noop, "9-bit": check_unknown, # unknown encoding } for enc in encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) # finally, make a part without content headers factories.PartListFactory(email=email, parent=first_part, body=body) # and now export message_object = make_message(email) for message_part in message_object.walk(): ct = message_part.get("Content-Type", None) cte = message_part.get("Content-Transfer-Encoding", None) if ct is None: # default is to assume 7-bit check_noop(message_part, body_data) self.assertEqual(message_part.get_payload(decode=True), body_data) elif ct.startswith("multipart/mixed"): pass else: encodings[cte](message_part, body_data) self.assertEqual(message_part.get_payload(decode=True), body_data)
def test_bad_css(self): """This test uses an example email that causes issue #47""" msg = mail.MailRequest("", "", "", EXAMPLE_PREMAILER_BROKEN_CSS) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_signed_forwarded_digest(self): msg = mail.MailRequest("", "", "", EXAMPLE_SIGNED_FORWARDED_DIGEST) make_email(msg, self.inbox) self.email = models.Email.objects.get() email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_unicode(self): """This test uses an example email that contains unicode chars""" msg = mail.MailRequest("", "", "", EXAMPLE_MISSING_CTE) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", message_object.as_bytes().decode()) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_bad_css(self): """This test uses an example email that causes issue #47""" msg = mail.MailRequest("", "", "", EXAMPLE_PREMAILER_BROKEN_CSS) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_signed_forwarded_digest(self): msg = mail.MailRequest("", "", "", EXAMPLE_SIGNED_FORWARDED_DIGEST) make_email(msg, self.inbox) self.email = models.Email.objects.get() email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", str(message_object)) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def test_unicode(self): """This test uses an example email that contains unicode chars""" msg = mail.MailRequest("", "", "", EXAMPLE_MISSING_CTE) make_email(msg, self.inbox) email = models.Email.objects.get() message_object = make_message(email) new_msg = mail.MailRequest("", "", "", message_object.as_bytes().decode()) self.assertEqual(len(msg.keys()), len(new_msg.keys())) self.assertEqual(len(list(msg.walk())), len(list(new_msg.walk())))
def liberate_message(mail_path, inbox, email_id): """ Take email from database and put on filesystem """ maildir = mailbox.Maildir(mail_path, factory=None).get_folder(inbox) try: msg = Email.objects.get(id=email_id, deleted=False) msg = utils.make_message(msg) maildir.add(msg.as_bytes()) except Exception as exc: msg_id = hex(int(email_id))[2:] log.warning("Exception processing %s", msg_id, exc_info=exc) return msg_id
def test_encoders_used(self): # make message with base64 part, uuencode part, 8bit part, 7bit part, # quopri part, and some invalid part unicode_body_data = "Hello\n\nHow are you?\nPó på pə pë\n".encode() ascii_body_data = "Hello\n\nHow are you?\n".encode() email = factories.EmailFactory(inbox=self.inbox) unicode_body = factories.BodyFactory(data=unicode_body_data) ascii_body = factories.BodyFactory(data=ascii_body_data) first_part = factories.PartListFactory( email=email, body=factories.BodyFactory(data=b"")) factories.HeaderFactory( part=first_part, name="Content-Type", data="multipart/mixed; boundary=\"=-3BRZDE/skgKPPh+RuFa/\"") unicode_encodings = { "base64": check_base64, "quoted-printable": check_quopri, "uuencode": check_uu, "x-uuencode": check_uu, "uue": check_uu, "x-uue": check_uu, } ascii_encodings = { "7-bit": check_noop, "8-bit": check_noop, "9-bit": check_unknown, # unknown encoding } encodings = {} encodings.update(unicode_encodings) encodings.update(ascii_encodings) for enc in unicode_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=unicode_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) for enc in ascii_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=ascii_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) # finally, make a part without content headers factories.PartListFactory(email=email, parent=first_part, body=ascii_body) # and now export message_object = make_message(email) for message_part in message_object.walk(): ct = message_part.get("Content-Type", None) cte = message_part.get("Content-Transfer-Encoding", None) if ct is None: # default is to assume 7-bit check_noop(message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif ct.startswith("multipart/mixed"): pass elif cte in ascii_encodings: encodings[cte](message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif cte in unicode_encodings: encodings[cte](message_part, unicode_body_data) self.assertEqual(message_part.get_payload(decode=True), unicode_body_data) else: raise AssertionError( "Unknown Content-Type or Content-Type-Encoding") # check that we can decode the whole lot in one go output_bytes = message_object.as_string().encode("ascii") self.assertNotEqual(len(output_bytes), 0) self.assertEqual( output_bytes.count(b"text/plain; name=\"my-file.txt\""), len(encodings))
def test_encoders_used(self): # make message with base64 part, uuencode part, 8bit part, 7bit part, # quopri part, and some invalid part unicode_body_data = "Hello\n\nHow are you?\nPó på pə pë\n".encode() ascii_body_data = "Hello\n\nHow are you?\n".encode() email = factories.EmailFactory(inbox=self.inbox) unicode_body = factories.BodyFactory(data=unicode_body_data) ascii_body = factories.BodyFactory(data=ascii_body_data) first_part = factories.PartListFactory(email=email, body=factories.BodyFactory(data=b"")) factories.HeaderFactory(part=first_part, name="Content-Type", data="multipart/mixed; boundary=\"=-3BRZDE/skgKPPh+RuFa/\"") unicode_encodings = { "base64": check_base64, "quoted-printable": check_quopri, "uuencode": check_uu, "x-uuencode": check_uu, "uue": check_uu, "x-uue": check_uu, } ascii_encodings = { "7-bit": check_noop, "8-bit": check_noop, "9-bit": check_unknown, # unknown encoding } encodings = {} encodings.update(unicode_encodings) encodings.update(ascii_encodings) for enc in unicode_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=unicode_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) for enc in ascii_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=ascii_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) # finally, make a part without content headers factories.PartListFactory(email=email, parent=first_part, body=ascii_body) # and now export message_object = make_message(email) for message_part in message_object.walk(): ct = message_part.get("Content-Type", None) cte = message_part.get("Content-Transfer-Encoding", None) if ct is None: # default is to assume 7-bit check_noop(message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif ct.startswith("multipart/mixed"): pass elif cte in ascii_encodings: encodings[cte](message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif cte in unicode_encodings: encodings[cte](message_part, unicode_body_data) self.assertEqual(message_part.get_payload(decode=True), unicode_body_data) else: raise AssertionError("Unknown Content-Type or Content-Type-Encoding") # check that we can decode the whole lot in one go output_bytes = message_object.as_string().encode("ascii") self.assertNotEqual(len(output_bytes), 0) self.assertEqual(output_bytes.count(b"text/plain; name=\"my-file.txt\""), len(encodings))