test_body.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. from textwrap import dedent
  2. from redmail import EmailSender
  3. import pytest
  4. from convert import remove_extra_lines, payloads_to_dict
  5. from getpass import getpass, getuser
  6. from platform import node
  7. from convert import remove_email_extra, remove_email_content_id, remove_email_message_id
  8. import platform
  9. PYTHON_VERSION = platform.sys.version_info
  10. IS_PY36 = PYTHON_VERSION.major == 3 and PYTHON_VERSION.minor == 6
  11. def test_text_message():
  12. sender = EmailSender(host=None, port=1234)
  13. msg = sender.get_message(
  14. sender="me@example.com",
  15. receivers="you@example.com",
  16. subject="Some news",
  17. text="Hi, nice to meet you.",
  18. )
  19. msg = remove_email_message_id(str(msg))
  20. assert str(msg) == dedent("""
  21. from: me@example.com
  22. subject: Some news
  23. to: you@example.com
  24. Message-ID: <<message_id>>
  25. Content-Type: text/plain; charset="utf-8"
  26. Content-Transfer-Encoding: 7bit
  27. MIME-Version: 1.0
  28. Hi, nice to meet you.
  29. """)[1:]
  30. def test_html_message():
  31. sender = EmailSender(host=None, port=1234)
  32. msg = sender.get_message(
  33. sender="me@example.com",
  34. receivers="you@example.com",
  35. subject="Some news",
  36. html="<h3>Hi,</h3><p>Nice to meet you</p>",
  37. )
  38. msg = remove_email_message_id(str(msg))
  39. assert remove_email_content_id(str(msg)) == dedent("""
  40. from: me@example.com
  41. subject: Some news
  42. to: you@example.com
  43. Message-ID: <<message_id>>
  44. Content-Type: multipart/mixed; boundary="===============<ID>=="
  45. --===============<ID>==
  46. Content-Type: multipart/alternative;
  47. boundary="===============<ID>=="
  48. --===============<ID>==
  49. Content-Type: text/html; charset="utf-8"
  50. Content-Transfer-Encoding: 7bit
  51. MIME-Version: 1.0
  52. <h3>Hi,</h3><p>Nice to meet you</p>
  53. --===============<ID>==--
  54. --===============<ID>==--
  55. """)[1:]
  56. def test_text_and_html_message():
  57. sender = EmailSender(host=None, port=1234)
  58. msg = sender.get_message(
  59. sender="me@example.com",
  60. receivers="you@example.com",
  61. subject="Some news",
  62. html="<h3>Hi,</h3><p>nice to meet you.</p>",
  63. text="Hi, nice to meet you.",
  64. )
  65. msg = remove_email_message_id(str(msg))
  66. assert remove_email_content_id(str(msg)) == dedent("""
  67. from: me@example.com
  68. subject: Some news
  69. to: you@example.com
  70. Message-ID: <<message_id>>
  71. MIME-Version: 1.0
  72. Content-Type: multipart/mixed; boundary="===============<ID>=="
  73. --===============<ID>==
  74. Content-Type: multipart/alternative;
  75. boundary="===============<ID>=="
  76. --===============<ID>==
  77. Content-Type: text/plain; charset="utf-8"
  78. Content-Transfer-Encoding: 7bit
  79. Hi, nice to meet you.
  80. --===============<ID>==
  81. Content-Type: text/html; charset="utf-8"
  82. Content-Transfer-Encoding: 7bit
  83. MIME-Version: 1.0
  84. <h3>Hi,</h3><p>nice to meet you.</p>
  85. --===============<ID>==--
  86. --===============<ID>==--
  87. """)[1:]
  88. @pytest.mark.parametrize(
  89. "html,expected_html,text,expected_text,extra", [
  90. pytest.param(
  91. "<h3>Hi,</h3> <p>This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.</p>",
  92. f"<h3>Hi,</h3> <p>This is {getuser()} from {node()}. I'm really Me.</p>\n",
  93. "Hi, \nThis is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.",
  94. f"Hi, \nThis is {getuser()} from {node()}. I'm really Me.\n",
  95. None,
  96. id="With default extras"
  97. ),
  98. pytest.param(
  99. "<h3>Hi {{ receiver }},</h3> <p>This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.</p>",
  100. f"<h3>Hi you,</h3> <p>This is overridden from {node()}. I'm really Me.</p>\n",
  101. "Hi {{ receiver }}, This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.",
  102. f"Hi you, This is overridden from {node()}. I'm really Me.\n",
  103. {"user": "overridden", "receiver": "you"},
  104. id="Custom extra"
  105. ),
  106. ]
  107. )
  108. def test_with_jinja_params(html, text, extra, expected_html, expected_text):
  109. sender = EmailSender(host=None, port=1234)
  110. msg = sender.get_message(
  111. sender="me@gmail.com",
  112. receivers="you@gmail.com",
  113. subject="Some news",
  114. text=text,
  115. html=html,
  116. body_params=extra
  117. )
  118. # Validate structure
  119. structure = payloads_to_dict(msg)
  120. assert structure == {
  121. 'multipart/mixed': {
  122. 'multipart/alternative': {
  123. 'text/plain': structure["multipart/mixed"]["multipart/alternative"]["text/plain"],
  124. 'text/html': structure["multipart/mixed"]["multipart/alternative"]["text/html"],
  125. }
  126. }
  127. }
  128. assert "multipart/mixed" == msg.get_content_type()
  129. alternative = msg.get_payload()[0]
  130. text_part, html_part = alternative.get_payload()
  131. text = remove_email_extra(text_part.get_payload())
  132. html = remove_email_extra(html_part.get_payload())
  133. assert expected_html == html
  134. assert expected_text == text
  135. @pytest.mark.parametrize("use_jinja_obj,use_jinja", [
  136. pytest.param(None, False, id="Use arg"),
  137. pytest.param(False, None, id="Use attr"),
  138. pytest.param(True, False, id="Override"),
  139. ])
  140. def test_without_jinja(use_jinja_obj, use_jinja):
  141. html = "<h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_name }}.</p>"
  142. text = "Hi, \nThis is {{ user }} from { node }. I'm really {{ sender.full_name }}."
  143. sender = EmailSender(host=None, port=1234)
  144. sender.use_jinja = use_jinja_obj
  145. msg = sender.get_message(
  146. sender="me@example.com",
  147. receivers="you@example.com",
  148. subject="Some news",
  149. text=text,
  150. html=html,
  151. use_jinja=use_jinja,
  152. )
  153. encoding = '7bit' if IS_PY36 else 'quoted-printable'
  154. expected = dedent("""
  155. from: me@example.com
  156. subject: Some news
  157. to: you@example.com
  158. Message-ID: <<message_id>>
  159. MIME-Version: 1.0
  160. Content-Type: multipart/mixed; boundary="===============<ID>=="
  161. --===============<ID>==
  162. Content-Type: multipart/alternative;
  163. boundary="===============<ID>=="
  164. --===============<ID>==
  165. Content-Type: text/plain; charset="utf-8"
  166. Content-Transfer-Encoding: 7bit
  167. Hi,
  168. This is {{ user }} from { node }. I'm really {{ sender.full_name }}.
  169. --===============<ID>==
  170. Content-Type: text/html; charset="utf-8"
  171. Content-Transfer-Encoding: """ + encoding + """
  172. MIME-Version: 1.0
  173. <h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_n=
  174. ame }}.</p>
  175. --===============<ID>==--
  176. --===============<ID>==--
  177. """)[1:]
  178. if IS_PY36:
  179. expected = expected.replace('sender.full_n=\n', 'sender.full_n')
  180. msg = remove_email_message_id(str(msg))
  181. assert remove_email_content_id(msg) == expected
  182. def test_with_error():
  183. sender = EmailSender(host=None, port=1234)
  184. try:
  185. raise RuntimeError("Deliberate failure")
  186. except:
  187. msg = sender.get_message(
  188. sender="me@gmail.com",
  189. receivers="you@gmail.com",
  190. subject="Some news",
  191. text="Error occurred \n{{ error }}",
  192. html="<h1>Error occurred: </h1>{{ error }}",
  193. )
  194. alternative = msg.get_payload()[0]
  195. text_part, html_part = alternative.get_payload()
  196. text = remove_email_extra(text_part.get_payload())
  197. html = remove_email_extra(html_part.get_payload())
  198. if IS_PY36:
  199. text = text.replace('Error occurred \n', 'Error occurred\n')
  200. html = html.replace('<span style="color:', '<span style=3D"color:')
  201. assert text.startswith('Error occurred\nTraceback (most recent call last):\n File "')
  202. assert text.endswith(', in test_with_error\n raise RuntimeError("Deliberate failure")\nRuntimeError: Deliberate failure\n')
  203. assert html.startswith('<h1>Error occurred: </h1>\n <div>\n <h4>Traceback (most recent call last):</h4>\n <pre><code> File &quot;')
  204. assert html.endswith(', in test_with_error\nraise RuntimeError(&quot;Deliberate failure&quot;)</code></pre>\n <span style=3D"color: red; font-weight: bold">Deliberate failure</span>: <span>RuntimeError</span>\n </div>\n')
  205. def test_set_defaults():
  206. email = EmailSender(host=None, port=1234)
  207. email.sender = 'me@gmail.com'
  208. email.receivers = ['you@gmail.com', 'they@gmail.com']
  209. email.subject = "Some email"
  210. msg = email.get_message(text="Hi, an email")
  211. headers = {
  212. key: val if key not in ('Message-ID',) else '<ID>'
  213. for key, val in msg.items()
  214. }
  215. assert {
  216. 'from': 'me@gmail.com',
  217. 'to': 'you@gmail.com, they@gmail.com',
  218. 'subject': 'Some email',
  219. 'Content-Type': 'text/plain; charset="utf-8"',
  220. 'Content-Transfer-Encoding': '7bit',
  221. 'MIME-Version': '1.0',
  222. 'Message-ID': '<ID>',
  223. } == headers
  224. def test_cc_bcc():
  225. email = EmailSender(host=None, port=1234)
  226. msg = email.get_message(sender="me@example.com", subject="Some email", cc=['you@example.com'], bcc=['he@example.com', 'she@example.com'])
  227. msg = remove_email_message_id(str(msg))
  228. assert remove_email_content_id(msg) == dedent("""
  229. from: me@example.com
  230. subject: Some email
  231. cc: you@example.com
  232. bcc: he@example.com, she@example.com
  233. Message-ID: <<message_id>>
  234. """)[1:]
  235. def test_missing_subject():
  236. email = EmailSender(host=None, port=1234)
  237. with pytest.raises(ValueError):
  238. email.get_message(sender="me@example.com", receivers=['you@example.com'])
  239. def test_no_table_templates():
  240. email = EmailSender(host="localhost", port=0)
  241. assert email.default_html_theme == "modest.html"
  242. assert email.default_text_theme == "pandas.txt"
  243. email.default_html_theme = None
  244. email.default_text_theme = None
  245. msg = email.get_message(
  246. sender="me@gmail.com",
  247. receivers="you@gmail.com",
  248. subject="Some news",
  249. text="An example",
  250. html="<h1>An example</h1>"
  251. )
  252. headers = {
  253. key: val
  254. for key, val in msg.items()
  255. if key not in ('Message-ID',)
  256. }
  257. assert headers == {
  258. 'from': 'me@gmail.com',
  259. 'subject': 'Some news',
  260. 'to': 'you@gmail.com',
  261. 'MIME-Version': '1.0',
  262. 'Content-Type': 'multipart/mixed',
  263. }