test_attachments.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. from redmail import EmailSender
  2. import base64
  3. from pathlib import Path
  4. import pytest
  5. from resources import get_mpl_fig, get_pil_image
  6. from convert import remove_extra_lines, payloads_to_dict
  7. def to_encoded(s:str):
  8. return str(base64.b64encode(s.encode()), 'ascii')
  9. def test_with_text():
  10. sender = EmailSender(host=None, port=1234)
  11. msg = sender.get_message(
  12. sender="me@gmail.com",
  13. receivers="you@gmail.com",
  14. subject="Some news",
  15. text="Hi, this is an email",
  16. attachments={'data.txt': "Some content"}
  17. )
  18. # Validate structure
  19. assert payloads_to_dict(msg) == {
  20. 'multipart/mixed': {
  21. 'application/octet-stream': 'U29tZSBjb250ZW50\n',
  22. 'text/plain': 'Hi, this is an email\n',
  23. }
  24. }
  25. assert msg.get_content_type() == "multipart/mixed"
  26. text, attachment = msg.get_payload()
  27. assert text.get_content_type() == 'text/plain'
  28. assert attachment.get_content_type() == 'application/octet-stream'
  29. assert text.get_payload() == "Hi, this is an email\n"
  30. filename = attachment.get_filename()
  31. data = attachment.get_payload()
  32. assert filename == 'data.txt'
  33. assert to_encoded("Some content") == data.replace('\n', '')
  34. def test_with_html():
  35. sender = EmailSender(host=None, port=1234)
  36. msg = sender.get_message(
  37. sender="me@gmail.com",
  38. receivers="you@gmail.com",
  39. subject="Some news",
  40. html="<h1>Hi, this is an email.</h1>",
  41. attachments={'data.txt': "Some content"}
  42. )
  43. # Validate structure
  44. assert payloads_to_dict(msg) == {
  45. 'multipart/mixed': {
  46. 'application/octet-stream': 'U29tZSBjb250ZW50\n',
  47. 'multipart/alternative': {
  48. 'text/html': '<h1>Hi, this is an email.</h1>\n'
  49. }
  50. }
  51. }
  52. assert msg.get_content_type() == "multipart/mixed"
  53. alternative, attachment = msg.get_payload()
  54. html = alternative.get_payload()[0]
  55. assert html.get_content_type() == 'text/html'
  56. assert attachment.get_content_type() == 'application/octet-stream'
  57. assert html.get_payload() == "<h1>Hi, this is an email.</h1>\n"
  58. filename = attachment.get_filename()
  59. data = attachment.get_payload()
  60. assert attachment.get_content_type() == 'application/octet-stream'
  61. assert filename == 'data.txt'
  62. assert to_encoded("Some content") == data.replace('\n', '')
  63. def test_with_text_and_html():
  64. sender = EmailSender(host=None, port=1234)
  65. msg = sender.get_message(
  66. sender="me@gmail.com",
  67. receivers="you@gmail.com",
  68. subject="Some news",
  69. text="Hi, this is an email.",
  70. html="<h1>Hi, this is an email.</h1>",
  71. attachments={'data.txt': "Some content"}
  72. )
  73. # Validate structure
  74. assert payloads_to_dict(msg) == {
  75. 'multipart/mixed': {
  76. 'application/octet-stream': 'U29tZSBjb250ZW50\n',
  77. 'multipart/alternative': {
  78. 'text/html': '<h1>Hi, this is an email.</h1>\n',
  79. 'text/plain': 'Hi, this is an email.\n'
  80. }
  81. }
  82. }
  83. assert msg.get_content_type() == "multipart/mixed"
  84. alternative, attachment = msg.get_payload()
  85. text, html = alternative.get_payload()
  86. assert text.get_content_type() == "text/plain"
  87. assert html.get_content_type() == "text/html"
  88. assert attachment.get_content_type() == 'application/octet-stream'
  89. assert text.get_payload() == 'Hi, this is an email.\n'
  90. assert html.get_payload() == '<h1>Hi, this is an email.</h1>\n'
  91. filename = attachment.get_filename()
  92. data = attachment.get_payload()
  93. assert filename == 'data.txt'
  94. assert to_encoded("Some content") == data.replace('\n', '')
  95. def test_no_body():
  96. sender = EmailSender(host=None, port=1234)
  97. msg = sender.get_message(
  98. sender="me@gmail.com",
  99. receivers="you@gmail.com",
  100. subject="Some news",
  101. attachments={'data.txt': 'Some content'}
  102. )
  103. # Validate structure
  104. assert payloads_to_dict(msg) == {
  105. 'multipart/mixed': {
  106. 'application/octet-stream': 'U29tZSBjb250ZW50\n',
  107. }
  108. }
  109. assert msg.get_content_type() == "multipart/mixed"
  110. assert len(msg.get_payload()) == 1
  111. attachment = msg.get_payload(0)
  112. assert attachment.get_content_type() == 'application/octet-stream'
  113. filename = attachment.get_filename()
  114. data = attachment.get_payload()
  115. assert filename == 'data.txt'
  116. assert to_encoded("Some content") == data.replace('\n', '')
  117. def test_dict_string():
  118. sender = EmailSender(host=None, port=1234)
  119. msg = sender.get_message(
  120. sender="me@gmail.com",
  121. receivers="you@gmail.com",
  122. subject="Some news",
  123. attachments={'data.txt': 'Some content'}
  124. )
  125. assert msg.get_content_type() == "multipart/mixed"
  126. attachment = msg.get_payload(0)
  127. filename = attachment.get_filename()
  128. data = attachment.get_payload()
  129. assert filename == 'data.txt'
  130. assert to_encoded("Some content") == data.replace('\n', '')
  131. def test_dict_bytes():
  132. sender = EmailSender(host=None, port=1234)
  133. msg = sender.get_message(
  134. sender="me@gmail.com",
  135. receivers="you@gmail.com",
  136. subject="Some news",
  137. attachments={'data.bin': bytes(10)}
  138. )
  139. assert msg.get_content_type() == "multipart/mixed"
  140. payload = msg.get_payload(0)
  141. filename = payload.get_filename()
  142. data = payload.get_payload()
  143. assert filename == 'data.bin'
  144. assert base64.b64encode(bytes(10)).decode() == data.replace('\n', '')
  145. def test_dict_path(tmpdir):
  146. file = tmpdir.join("data.txt")
  147. file.write("Some content")
  148. sender = EmailSender(host=None, port=1234)
  149. msg = sender.get_message(
  150. sender="me@gmail.com",
  151. receivers="you@gmail.com",
  152. subject="Some news",
  153. attachments={'myfile.txt': Path(str(file))}
  154. )
  155. assert msg.get_content_type() == "multipart/mixed"
  156. payload = msg.get_payload(0)
  157. filename = payload.get_filename()
  158. data = payload.get_payload()
  159. assert filename == 'myfile.txt'
  160. assert to_encoded("Some content") == data.replace('\n', '')
  161. def test_dict_dataframe_txt():
  162. pytest.importorskip("pandas")
  163. import pandas as pd
  164. sender = EmailSender(host=None, port=1234)
  165. msg = sender.get_message(
  166. sender="me@gmail.com",
  167. receivers="you@gmail.com",
  168. subject="Some news",
  169. attachments={'myfile.txt': pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']})}
  170. )
  171. expected = str(pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']}))
  172. assert msg.get_content_type() == "multipart/mixed"
  173. payload = msg.get_payload(0)
  174. filename = payload.get_filename()
  175. data = payload.get_payload()
  176. assert filename == 'myfile.txt'
  177. assert to_encoded(expected) == data.replace('\n', '')
  178. def test_dict_dataframe_csv():
  179. pytest.importorskip("pandas")
  180. import pandas as pd
  181. df = pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']})
  182. sender = EmailSender(host=None, port=1234)
  183. msg = sender.get_message(
  184. sender="me@gmail.com",
  185. receivers="you@gmail.com",
  186. subject="Some news",
  187. attachments={'myfile.csv': df}
  188. )
  189. assert msg.get_content_type() == "multipart/mixed"
  190. payload = msg.get_payload(0)
  191. filename = payload.get_filename()
  192. data = payload.get_payload()
  193. assert filename == 'myfile.csv'
  194. assert to_encoded(df.to_csv()) == data.replace('\n', '')
  195. def test_dict_dataframe_html():
  196. pytest.importorskip("pandas")
  197. import pandas as pd
  198. sender = EmailSender(host=None, port=1234)
  199. msg = sender.get_message(
  200. sender="me@gmail.com",
  201. receivers="you@gmail.com",
  202. subject="Some news",
  203. attachments={'myfile.html': pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']})}
  204. )
  205. expected = '<table border="1" class="dataframe">\n <thead>\n <tr style="text-align: right;">\n <th></th>\n <th>a</th>\n <th>b</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>1</td>\n <td>1</td>\n </tr>\n <tr>\n <th>1</th>\n <td>2</td>\n <td>2</td>\n </tr>\n <tr>\n <th>2</th>\n <td>3</td>\n <td>3</td>\n </tr>\n </tbody>\n</table>'
  206. assert msg.get_content_type() == "multipart/mixed"
  207. payload = msg.get_payload(0)
  208. filename = payload.get_filename()
  209. data = payload.get_payload().replace('\n', '')
  210. assert filename == 'myfile.html'
  211. assert to_encoded(expected) == data
  212. def test_dict_dataframe_invalid():
  213. pytest.importorskip("pandas")
  214. import pandas as pd
  215. sender = EmailSender(host=None, port=1234)
  216. with pytest.raises(ValueError):
  217. msg = sender.get_message(
  218. sender="me@gmail.com",
  219. receivers="you@gmail.com",
  220. subject="Some news",
  221. attachments={'myfile.something': pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']})}
  222. )
  223. def test_dict_dataframe_excel_no_error():
  224. pytest.importorskip("pandas")
  225. pytest.importorskip("openpyxl")
  226. import pandas as pd
  227. sender = EmailSender(host=None, port=1234)
  228. msg = sender.get_message(
  229. sender="me@gmail.com",
  230. receivers="you@gmail.com",
  231. subject="Some news",
  232. attachments={'myfile.xlsx': pd.DataFrame({'a': [1,2,3], 'b': ['1', '2', '3']})}
  233. )
  234. assert msg.get_content_type() == "multipart/mixed"
  235. payload = msg.get_payload(0)
  236. filename = payload.get_filename()
  237. data = payload.get_payload()
  238. assert filename == 'myfile.xlsx'
  239. # Excels are harder to verify
  240. def test_dict_pil_no_error():
  241. pil, bytes_img = get_pil_image()
  242. sender = EmailSender(host=None, port=1234)
  243. msg = sender.get_message(
  244. sender="me@gmail.com",
  245. receivers="you@gmail.com",
  246. subject="Some news",
  247. attachments={'myimg.png': pil}
  248. )
  249. assert msg.get_content_type() == "multipart/mixed"
  250. payload = msg.get_payload(0)
  251. filename = payload.get_filename()
  252. data = payload.get_payload()
  253. assert filename == 'myimg.png'
  254. assert str(base64.b64encode(bytes_img), 'ascii') == data.replace('\n', '')
  255. def test_dict_matplotlib_no_error():
  256. fig, bytes_fig = get_mpl_fig()
  257. sender = EmailSender(host=None, port=1234)
  258. msg = sender.get_message(
  259. sender="me@gmail.com",
  260. receivers="you@gmail.com",
  261. subject="Some news",
  262. attachments={'myimg.png': fig}
  263. )
  264. assert msg.get_content_type() == "multipart/mixed"
  265. payload = msg.get_payload(0)
  266. filename = payload.get_filename()
  267. data = payload.get_payload()
  268. assert filename == 'myimg.png'
  269. assert str(base64.b64encode(bytes_fig), 'ascii') == data.replace('\n', '')
  270. def test_dict_invalid():
  271. sender = EmailSender(host=None, port=1234)
  272. with pytest.raises(TypeError):
  273. msg = sender.get_message(
  274. sender="me@gmail.com",
  275. receivers="you@gmail.com",
  276. subject="Some news",
  277. attachments={'myimg.png': sender}
  278. )
  279. def test_dict_invalid_key():
  280. fig, bytes_fig = get_mpl_fig()
  281. sender = EmailSender(host=None, port=1234)
  282. with pytest.raises(TypeError):
  283. msg = sender.get_message(
  284. sender="me@gmail.com",
  285. receivers="you@gmail.com",
  286. subject="Some news",
  287. attachments={sender: 'something'}
  288. )
  289. def test_dict_multiple(tmpdir):
  290. file1 = tmpdir.join("file_1.txt")
  291. file1.write("Some content 1")
  292. file2 = tmpdir.join("file_2.txt")
  293. file2.write("Some content 2")
  294. sender = EmailSender(host=None, port=1234)
  295. msg = sender.get_message(
  296. sender="me@gmail.com",
  297. receivers="you@gmail.com",
  298. subject="Some news",
  299. attachments={'data_1.txt': Path(file1), 'data_2.txt': Path(file2)}
  300. )
  301. assert msg.get_content_type() == "multipart/mixed"
  302. expected = [('data_1.txt', 'Some content 1'), ('data_2.txt', 'Some content 2')]
  303. for payload, expected in zip(msg.iter_attachments(), expected):
  304. filename = payload.get_filename()
  305. data = payload.get_payload()
  306. assert filename == expected[0]
  307. assert to_encoded(expected[1]) == data.replace('\n', '')
  308. # List attachments
  309. # ----------------
  310. def test_list_path(tmpdir):
  311. file = tmpdir.join("data.txt")
  312. file.write("Some content")
  313. sender = EmailSender(host=None, port=1234)
  314. msg = sender.get_message(
  315. sender="me@gmail.com",
  316. receivers="you@gmail.com",
  317. subject="Some news",
  318. attachments=[Path(str(file))]
  319. )
  320. assert msg.get_content_type() == "multipart/mixed"
  321. payload = msg.get_payload(0)
  322. filename = payload.get_filename()
  323. data = payload.get_payload()
  324. assert filename == 'data.txt'
  325. assert to_encoded("Some content") == data.replace('\n', '')
  326. def test_list_string_path(tmpdir):
  327. file = tmpdir.join("data.txt")
  328. file.write("Some content")
  329. sender = EmailSender(host=None, port=1234)
  330. msg = sender.get_message(
  331. sender="me@gmail.com",
  332. receivers="you@gmail.com",
  333. subject="Some news",
  334. attachments=[str(file)]
  335. )
  336. assert msg.get_content_type() == "multipart/mixed"
  337. payload = msg.get_payload(0)
  338. filename = payload.get_filename()
  339. data = payload.get_payload()
  340. assert filename == 'data.txt'
  341. assert to_encoded("Some content") == data.replace('\n', '')
  342. def test_list_string_error():
  343. sender = EmailSender(host=None, port=1234)
  344. with pytest.raises(ValueError):
  345. msg = sender.get_message(
  346. sender="me@gmail.com",
  347. receivers="you@gmail.com",
  348. subject="Some news",
  349. attachments=['just something']
  350. )
  351. def test_list_multiple(tmpdir):
  352. file1 = tmpdir.join("data_1.txt")
  353. file1.write("Some content 1")
  354. file2 = tmpdir.join("data_2.txt")
  355. file2.write("Some content 2")
  356. sender = EmailSender(host=None, port=1234)
  357. msg = sender.get_message(
  358. sender="me@gmail.com",
  359. receivers="you@gmail.com",
  360. subject="Some news",
  361. attachments=[Path(str(file1)), Path(str(file2))]
  362. )
  363. assert msg.get_content_type() == "multipart/mixed"
  364. expected = [('data_1.txt', 'Some content 1'), ('data_2.txt', 'Some content 2')]
  365. for payload, expected in zip(msg.iter_attachments(), expected):
  366. filename = payload.get_filename()
  367. data = payload.get_payload()
  368. assert filename == expected[0]
  369. assert to_encoded(expected[1]) == data.replace('\n', '')
  370. def test_list_invalid():
  371. sender = EmailSender(host=None, port=1234)
  372. with pytest.raises(TypeError):
  373. msg = sender.get_message(
  374. sender="me@gmail.com",
  375. receivers="you@gmail.com",
  376. subject="Some news",
  377. attachments=[sender]
  378. )
  379. def test_string_path(tmpdir):
  380. file = tmpdir.join("data.txt")
  381. file.write("Some content")
  382. sender = EmailSender(host=None, port=1234)
  383. msg = sender.get_message(
  384. sender="me@gmail.com",
  385. receivers="you@gmail.com",
  386. subject="Some news",
  387. attachments=str(file)
  388. )
  389. assert msg.get_content_type() == "multipart/mixed"
  390. payload = msg.get_payload(0)
  391. filename = payload.get_filename()
  392. data = payload.get_payload()
  393. assert filename == 'data.txt'
  394. assert to_encoded("Some content") == data.replace('\n', '')
  395. def test_string_error():
  396. sender = EmailSender(host=None, port=1234)
  397. with pytest.raises(ValueError):
  398. msg = sender.get_message(
  399. sender="me@gmail.com",
  400. receivers="you@gmail.com",
  401. subject="Some news",
  402. attachments="just something"
  403. )
  404. def test_path(tmpdir):
  405. file = tmpdir.join("data.txt")
  406. file.write("Some content")
  407. sender = EmailSender(host=None, port=1234)
  408. msg = sender.get_message(
  409. sender="me@gmail.com",
  410. receivers="you@gmail.com",
  411. subject="Some news",
  412. attachments=Path(file)
  413. )
  414. assert msg.get_content_type() == "multipart/mixed"
  415. payload = msg.get_payload(0)
  416. filename = payload.get_filename()
  417. data = payload.get_payload()
  418. assert filename == 'data.txt'
  419. assert to_encoded("Some content") == data.replace('\n', '')