errands
small jobs the runtime does for the studio.
git clone https://owenrusk.dev/errands.git
errands / tests/test_mail.py -rw-r--r-- · 3388 bytes
1 import mailbox
2 import tempfile
3 import unittest
4 from email.message import EmailMessage
5 from pathlib import Path
6
7 from errands import mail, settings
8 from tests.fakes import FakeBox, FakeServer, raw
9
10
11 class UnreadTest(unittest.TestCase):
12 def test_reads_every_unseen_message(self):
13 box = FakeBox({b"7": raw(subject="a question"), b"9": raw(sender="Ann <Ann@example.com>")})
14 got = mail.unread(lambda: box)
15 self.assertEqual([m.uid for m in got], ["7", "9"])
16 self.assertEqual(got[0].subject, "a question")
17 self.assertEqual(got[1].sender, "ann@example.com")
18 self.assertEqual(got[0].body, "hello\n")
19 self.assertTrue(box.closed)
20
21 def test_plain_text_from_multipart(self):
22 msg = EmailMessage()
23 msg["From"] = "someone@example.com"
24 msg["Subject"] = "screenshot"
25 msg.set_content("it's attached\n")
26 msg.add_alternative("<p>it's attached</p>", subtype="html")
27 msg.add_attachment(b"\x89PNG", maintype="image", subtype="png", filename="shot.png")
28 self.assertEqual(mail.parse("3", bytes(msg)).body, "it's attached\n")
29
30 def test_encoded_subject(self):
31 message = mail.parse("4", raw(subject="caf\u00e9 hours"))
32 self.assertEqual(message.subject, "caf\u00e9 hours")
33 self.assertIn(b"=?utf-8?", raw(subject="caf\u00e9 hours"))
34
35 def test_skips_our_own(self):
36 box = FakeBox({b"1": raw(sender="Paper Moth Games <support@papermothgames.com>"), b"2": raw()})
37 self.assertEqual([m.uid for m in mail.unread(lambda: box)], ["2"])
38
39 def test_nothing_unread(self):
40 self.assertEqual(mail.unread(lambda: FakeBox({})), [])
41
42 def test_mark_read(self):
43 box = FakeBox({})
44 mail.mark_read("7", lambda: box)
45 self.assertEqual(box.stored, [("7", "+FLAGS", "(\\Seen)")])
46
47
48 class SendTest(unittest.TestCase):
49 def setUp(self):
50 self.dir = tempfile.TemporaryDirectory()
51 self.logs = settings.LOGS
52 settings.LOGS = Path(self.dir.name)
53
54 def tearDown(self):
55 settings.LOGS = self.logs
56 self.dir.cleanup()
57
58 def test_keeps_a_copy(self):
59 mail.send(mail.compose("someone@example.com", "hello", "hello\n"), FakeServer)
60 mail.send(mail.compose("ann@example.com", "again", "hello\n"), FakeServer)
61 kept = mailbox.mbox(settings.LOGS / "sent.mbox")
62 self.assertEqual([m["To"] for m in kept], ["someone@example.com", "ann@example.com"])
63 kept.close()
64
65 def test_reply_keeps_the_subject_and_thread(self):
66 original = mail.parse("7", raw(subject="a question", message_id="<q@example.com>"))
67 server = FakeServer()
68 mail.reply(original, "thanks for writing.\n", lambda: server)
69 sent = server.sent[0]
70 self.assertEqual(sent["To"], "someone@example.com")
71 self.assertEqual(sent["Subject"], "Re: a question")
72 self.assertEqual(sent["In-Reply-To"], "<q@example.com>")
73 self.assertEqual(sent["References"], "<q@example.com>")
74 self.assertEqual(sent["From"], "Paper Moth Games <support@papermothgames.com>")
75 self.assertTrue(server.quit_called)
76
77 def test_no_second_re(self):
78 original = mail.parse("7", raw(subject="Re: a question"))
79 server = FakeServer()
80 mail.reply(original, "ok\n", lambda: server)
81 self.assertEqual(server.sent[0]["Subject"], "Re: a question")